tag:blogger.com,1999:blog-19849321240879436602024-02-08T06:20:56.334+01:00Kio's Hardware ProjectsThis is about my hardware projects, mostly my self-built CPU K1-16/16 and some AVR projects.Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.comBlogger49125tag:blogger.com,1999:blog-1984932124087943660.post-37766675383319923592016-05-29T20:10:00.000+02:002016-05-29T20:21:06.897+02:00Hit the Ceiling – Going Virtual<h1>Hit the Ceiling – Going Virtual</h1><p>End April i hit the ceiling. I'm very tall, but that's not the reason – the code size for the z80 system reached 32 kBytes. <br />
I was working on the file system and when it was in a state where it compiled – just half way done – the resulting rom size was only a tiny amount below 32 kB. </p><h2>So what could i do?</h2><p>I could remove all test code, and then i could use <i>z88dk</i> which allegedly creates slightly smaller code, but that would probably not really help: I'd just die later.</p><p>I could write everything in assembler.</p><p>Or i could finish the z80 backend for <i>Vcc</i>, my 'virtual code compiler'.</p><p>I couldn't decide on whether to create real z80 code or virtual code for a Forth-style interpreter. So i implemented them both, mostly. While programming i made some measurements.</p><h4>Compare virtual code with native z80 code, running the opcode test program:</h4><pre style="background-color: #fff2cc;"> <b><u>virtual code</u> <u>z80 code</u></b>
total rom size 10935 11455 bytes
= code blob 5811 4428 bytes
+ test code 5128 7027 bytes
time 3.630s 2.376s
</pre><p>In this not representative program the z80 code is 37% bigger and 35% faster than virtual code. (The 'code blob' is the support library; 'test code' is what grows.)</p><h4>I have also compiled my serial driver in various versions.</h4><pre style="background-color: #fff2cc;">sdcc 1974 bytes
Vcc z80 code 1520 bytes
Vcc virtual code 1169 bytes
</pre><p>The z80 code generated by <i>Vcc</i> is 23% shorter than that of <i>sdcc</i>, and the virtual code is even 40% shorter than <i>sdcc</i> z80 code or 23% shorter than <i>Vcc</i> z80 code.</p><p>When i worked on the z80 backend, i was a little bit frustrated about the little amount of code size reduction i could achieve, though i used all 'illegal' tricks, e.g. i use the RST opcodes for the most frequent building blocks to reduce code size.</p><p>The code shrink of approx. 25% is simply not enough, because it does not take into account the size of the static support code blob. This is currently at 4428 bytes and i expect a final size of around 8 kB, after adding all int32 code and if i leave out floating point. That is 25% of the rom size of 32 kB. So before i actually save space, the code size must be reduced by at least 25%. And this looks like the maximum i can achieve with my z80 backend. (though 'nothing saved' is only true for code in rom. Any program loaded into ram will see the full size reduction. And i neglect that <i>sdcc</i> pulls in some library code as well…)</p><p>The code shrink of 40% of the virtual code version looks much better, though it will have a slightly larger support code blob. And it will come at a price: <i><b>Speed…</b></i></p><h4>Before i go into details here a comparison of the compiler outputs of a simple function:</h4><p><b>Vcc:</b></p><pre style="background-color: #fff2cc;">uint8 avail_out(SerialDevice¢ channel)
{
return obusz - (channel.obuwi-channel.oburi);
}
</pre><p><b>C:</b></p><pre style="background-color: #fff2cc;">uint8 sio_avail_out(SerialDevice* channel)
{
return obusz - (channel->obuwi - channel->oburi);
}
</pre><p>This function determines how many free space is left in a sio output buffer. The <i>Vcc</i> function is a member function. 'channel' is a struct, 'obuwi' = output buffer write index, 'oburi' = output buffer read index, 'obusz' = output buffer size. I hope you get it.</p><p><b>sdcc</b>: In the case of such a short function, <i>sdcc</i> creates very good code. But don't be fooled: if it can no longer keep everything in registers, the code becomes ugly… So this is actually not a representative example for <i>sdcc</i>. [25 bytes total]</p><pre style="background-color: #fff2cc;">_sio_avail_out::
pop de ; return address
pop bc ; 'channel'
push bc ; everything back:
push de ; caller is responsible for cleaning up the stack…
push bc
pop iy ; iy = 'channel'
ld e,15 (iy)
ld l, c ; superfluous
ld h, b ; superfluous
ld bc, #0x0010 ; load into hl instead
add hl, bc
ld c,(hl)
ld a,e
sub a, c
ld c,a
ld a,#0x40
sub a, c
ld l,a
ret
</pre><p><b>hand-coded assembler</b>: This is for the <i>Vcc</i> memory model with 'handles', so i must dereference a pointer to a pointer to the struct data. And as i see by the last instruction, it's for the virtual code machine: [19 bytes total]</p><pre style="background-color: #fff2cc;">sio_avail_out:: ; in: de -> -> channel
ex hl,de ; hl -> -> channel
ld e,(hl)
inc hl
ld d,(hl) ; de -> channel
ld a,obusz ; a=obusz
ld hl,obuwi
add hl,de ; hl -> channel.obuwi
sub a,(hl) ; a=obusz-obuwi
inc hl ; hl -> oburi
add a,(hl) ; a=obusz-obuwi+oburi
ld e,a
ld d,0 ; out: de = return value
jp next ; jump to next opcode
</pre><p><b>Z80 code created by <i>Vcc</i></b>. It's an early state and there are some optimizations left. It looks poor when compared with the <i>sdcc</i> generated code, but as already said, things become different for functions with more than one line of code. Then this code is still representative but <i>sdcc</i> looks poor too. The first line is a program label, though a little bit longish. <span style="background:#6f6">:-)</span> But if you compare it with the function's signature then it hopefully makes sense. [total 36 bytes]</p><pre style="background-color: #fff2cc;">SerialDevice.avail_out__12SerialDeviceC_5uint8:
pop hl ; move the return address to the VM's return stack
call pushr_hl
rst ivalu8 ; push obusz: 'ivalu8' = immediate uint8 value
db 64
push de
ld l,2+2 ; get local variable 'channel'
rst lget ; 'lget' = get local variable
ld hl,15 ; get item 'obuwi' at offset 15
rst igetu8 ; 'igetu8' = get uint8 struct item
push de
ld l,4+2 ; get local variable 'channel'
rst lget
ld hl,16 ; get item 'oburi' at offset 16
rst igetu8
pop hl
and a ; subtract obuwi - oburi
sbc hl,de
ex hl,de
pop hl
and a ; subtract obusz - (obuwi - oburi)
sbc hl,de
ex hl,de
pop af ; discard 2nd value on stack (the 'channel')
jp return ; get back the return address and return
</pre><p><b>Virtual code created by <i>Vcc</i></b> with minimum optimization: [29 bytes total]</p><pre style="background-color: #fff2cc;">SerialDevice.avail_out__12SerialDeviceC_5uint8:
rst p_enter ; the proc is entered in z80 code: switch to virtual code
dw IVAL, 64 ; push obusz
dw LGET ; get local variable 'channel'
db 2
dw IGETu8 ; get item 'obuwi' at offset 15
db 15
dw LGET ; get local variable 'channel'
db 4
dw IGETu8 ; get item 'oburi' at offset 16
db 16
dw SUB ; subtract obuwi - oburi
dw SUB ; subtract obusz - (obuwi - oburi)
dw TOR ; nip 2nd value on stack (the 'channel')
dw DROP ; by temporarily moving the top value to the return stack
dw FROMR ; and droping the 'channel'
dw RETURN
</pre><p><b>Virtual code created by <i>Vcc</i></b> after proper optimization: [20 bytes total]</p><pre style="background-color: #fff2cc;">SerialDevice.avail_out__12SerialDeviceC_5uint8:
rst p_enter
dw IVALu8 ; uint8 opcode with 1-byte argument
db 64
dw OVER ; instead of LGET 2
dw IGETu8
db 15
dw OVER2 ; instead of LGET 4
dw IGETu8
db 16
dw SUB
dw SUB
dw NIP0RETURN - 1 ; nip one value (the 'channel') and return
</pre><h4>One astonishing difference between z80 code and virtual code is: <i><b>optimization</b></i>.</h4><p>When you optimize z80 code, the following equation is true:</p><pre style="background-color: #ccffcc;">codesize = speed
</pre><p>The bigger your code, the higher the speed. Every effort to increase speed results in bigger code.</p><p>When you optimize virtual code, this equation is true:</p><pre style="background-color: #ccffcc;">codesize = 1 / speed
</pre><p>Whenever you reduce code size, the speed goes up. This is because the standard method to optimize virtual code is to create 'combi opcodes' for frequently occurring opcode pairs, which eliminates one opcode fetch. As a result it is much more fun to optimize virtual code because you are rewarded twice. <span style="background:#6f6">:-)</span> Though caveat: the size of the support code blob grows! <span style="background:#f66">:-(</span></p>Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com1tag:blogger.com,1999:blog-1984932124087943660.post-52678991433249377532016-04-27T21:29:00.001+02:002016-04-27T21:29:51.302+02:00One of the most useless features in C<p>While writing code for a "file descriptor" which imposes an array of function pointers, i stumbled over a "problem" which i first thought was an error in <i>sdcc</i>. In order to <a href="https://sourceforge.net/p/sdcc/bugs/2496/">report the error</a> i simplified the source until it only consisted of these 4 lines:</p><pre style="background-color: #fff2cc;">typedef int (*MyFPtr)(struct Data*);
struct Data { int a; };
extern int bar(struct Data* f);
MyFPtr foo = bar;
</pre><p>➜ I make a typedef for a function pointer, because function pointers are so awkward in c (though they are a pretty compared to function pointers in c++ ... which resulted in the invention of the data type 'auto' ...)<br />
Then at some point i actually define the struct.<br />
Later i declare a function which matches the typedef.<br />
Finally i try to assign this function to a function pointer variable. </p><p>compiling this source resulted in an error for the last line:</p><pre style="background-color: #fff2cc;">/foo-1.c:4: error 78: incompatible types
from type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed'
to type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed'
/foo-1.c:5: error 78: incompatible types
from type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed'
to type 'unsigned-int function ( struct Data generic* fixed) __reentrant fixed'
</pre><p>btw.: ignore the double error. Error messages in <i>sdcc</i> are always a little bit suboptimal.</p><p>This looked as if the compiler had a problem to see that too identical types are identical.</p><h3>And indeed they aren't.</h3><p>As i learned from my bug report, the first line implicitly declares a <u>local</u> data type. Local to – yes, i don't know exactly to what. But it's local. And so it's different to the later and globally defined struct.</p><p>One suggested solution was:</p><pre style="background-color: #fff2cc;">typedef unsigned int (*T)(struct Data*);
extern unsigned int foo(struct Data* f);
T bar = foo;
</pre><p>which compiled without error. But this now was actually an error in <i>sdcc</i>: This source is wrong too:<br />
Line 1 and 2 both declare local data types which by that are different. Line 3 shouldn't work. That there was an error could be proved by actually trying to use the function pointer typedef:</p><pre style="background-color: #fff2cc;">typedef unsigned int (*T)(struct Data*); // local data type
extern unsigned int foo(struct Data* f); // local data type
T bar = foo; // works in <i>sdcc</i> but shouldn't
struct Data { unsigned int a; };
int main() { struct Data d = {0}; foo(&d); } // rejected
</pre><h3>This lead me to the question:</h3><p>For what is the implicit declaration of a local data type in a function's argument list good, anyway? I can't think of a real use case. It's near impossible to call such a function. You have to cast the <u>function</u> to a function which accepts the data type you actually have, because you cannot even cast your data to the local data type... </p><p>Second, it's just a pitfall: If you declared the data type before the typedef and before the function declaration or definition, then the global data type is used. If you didn't, then a local data type is used. Imagine a local variable <b><tt>a</tt></b> in a function body was local <u>only</u> if there was no global variable <b><tt>a</tt></b> defined before…</p>Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-35909277615958189532016-04-20T19:55:00.001+02:002016-04-20T19:55:26.571+02:00Firmware Download and Access to IDE Board<p>Two topics in this post:</p><ul><li>Firmware download</li>
<li>Access IDE board, IDE and CF devices</li>
</ul><h3>Firmware download</h3><p>After my explorations into CRC generation, i worked on the firmware download code. This code has to run in RAM, because the eeprom can't be read while it is busy writing a block of data into it's cells.</p><p>I tried to keep things simple, and so the program flow looks like this:<br />
<a href = "http://k1.spdns.de/Develop/Hardware/K1-Bus%20Z80%20CPU%20board%20with%20SRAM/Emulator/Firmware%202016-04-16/util/write%20eeprom.s">write_eeprom.s</a></p><pre style="background-color: #fff2cc;">1. wait for SIO output to become empty
2. disable interrupts
3. receive magic header bytes
if they are wrong: bail out
4. copy code from rom into ram
jump to 6.
in ram:
5. Retry: receive bytes until magic header detected
6. in a loop:
7. receive 64 bytes of data (last block may be shorter)
update the crc after each byte
8. write block of data into eeprom
9. wait while eeprom busy
10. loop
11. receive and check crc:
error: print a message, flush input, wait for a key and retry at 5
ok: print a message, flush input, wait for a key and reset
</pre><p>Already complicated enough.</p><p>ad 1: I wait for the SIO output to become empty, because there may be (and typically are) some bytes left in the output buffer, and as soon as i disable interrupts they will never be sent. This resulted in truncated "last messages".</p><p>ad 7: The program receives blocks of 64 bytes, which is the eeprom's block size, writes them into the eeprom and reuses the receive buffer for the next block. It does not keep the bytes around until all bytes are received, so the whole eeprom can be reprogrammed, though i have only 32k of RAM minus approx. 1k for code and buffers available. </p><p>The program actively polls the UART and retrieves the bytes as soon as they pop up in the UART queue. Then it immediately updates the CRC, so no extra loop is needed for CRC calculation.</p><p>The data is written into the eeprom despite the CRC is not yet checked, which can only be done at the end of the transmission.</p><p>ad 9: Waiting for the eeprom takes up to 10 ms (acc. to Atmel docs). During this time i do not poll the UART, for simplicity. And i do not use any flow control. Currently the UART is programmed to 9600 Baud, which means 960 characters per second or 9.6 characters per 10 ms. The UART has an input queue of 16 bytes: The UART is doing my job! <b style="background:#6f6;">:-)</b></p><p>ad 11: Up to now i never had a CRC error.</p><p><b>Overall workflow is now like this:</b></p><pre style="background-color: #fff2cc;">1. Work on the source, compile & assemble the rom.
2. Launch the new rom in the emulator
The emulator silently creates a download file from the bare rom file.
3. Connect to the board (most times CoolTerm _is_ connected…)
4. Select "download firmware" from the menu presented by the board
5. upload a "Textfile" in CoolTerm
6. type A letter to reboot
</pre><p>The upload including writing to the eeprom now takes exactly as long as uploading the rom itself: 1 second per 960 bytes. Currently roughly 20 seconds.</p><p style="color:#0c0"><b>Kio:</b> "See Stager, that's how it works!"</p><p>Next i made a modification to the rom, uploaded it and found, that it no longer booted.</p><p style="color:#0c0"><b>Stager:</b> "See Kio, you still need me…" <b style="background:#f66;">:-(</b></p><h3>Access the IDE board</h3><p>Now that turn-around cycles are much faster and less painful, i started first tests to access the IDE board.</p><p>I talked to the i²c eeprom on the board... and it answered! :-)</p><p>Then i collected all my knowledge about IDE, which mostly centers around the <a href="http://velesoft.speccy.cz/zx/divide/">DivIDE</a> emulation in <a href="http://k1.spdns.de/Develop/Projects/zxsp-osx/Distributions/">zxsp</a>, and made up my mind on what to send to and read from the IDE device at first.</p><p><b>The test program looks roughly like this:</b></p><pre style="background-color: #fff2cc;">1. disable interrupts (in c: you remember the __critical bug?)
2. select the IDE board
3. read status and error register (from master, which is selected after reset)
4. print something
5. wait for ready and !busy in the status register
6. check that the device is not unexpectedly waiting for data
7. finally: issue command "IDENTIFY"
8. wait for data request in the status register, bail out on unexpected state
9. read 256 words into a sector buffer
10. read status and error register
11. print the sector data in hex
12. inspect and print various fields in the sector data
</pre><p>ad 1: Currently i'm back to the sdcc 3.6 nightly build, though it produced the so much slower code than version 3.4.</p><p>ad 2: As you may know, if you have followed this blog for the last years <b style="background:#ff6;">B-)</b> boards attached to the K1 bus must be "selected" and from that on any i/o goes to that board. This really is a nice method and i'm really happy with it. I just must make sure that i'm not interrupted while i'm working with a device, as the interrupt (sic!) will probably leave some other board selected…</p><p>ad 9: I really read 256 <u>words</u>, not 512 bytes. (Though, in essence off course i do read 512 bytes.) The K1 bus is a 16 bit bus and the Z80 board contains two 8-bit buffers for sending and receiving the high word. Then reading 16 bit values works like this:</p><p><b>Implementation of a function for c:</b></p><pre style="background-color: #fff2cc;">; uint16 in_w( uint8 addr ) __z88dk_fastcall;
;
_in_w::
ld a,l ; a = register address
or a,k1_rd_data ; add bits to access the bus
ld c,a
in l,(c) ; read the low byte
ld c,k1_rd_hi ; access the high-byte register
in h,(c) ; read the high byte from the high-byte register
ret
</pre><p>The function is marked as <tt>__z88dk_fastcall</tt>, which is really funny. <i>z88dk</i> is the (only?) competitor of <i>sdcc</i> in the field of Z80. <tt>__z88dk_fastcall</tt> means, that the argument to the function, which must have exactly one argument, is passed in <tt>l</tt>, <tt>hl</tt> or <tt>hlde</tt>, depending on size, and not on the stack. In my opinion this should be the default.</p><h3>PQI DOM, CF cards and Seagate ST1</h3><p>For some reason it first didn't work, but then, out of a sudden, i got good looking data from a device. The only thing i did to make it happen was, to scrutinize the circuit diagram for errors. And as soon as i could prove there was no error, reality was modified to match my expectations. Check. <b style="color: green;">✓</b></p><p>Off course the ascii texts of model name etc. were byte-swapped in the first version. Probably most people fall into this pitfall. The 4-byte values were calculated wrong in one place but correctly in another. After a few iterations the output from the "built-in" PQI DiskOnModule looked like this:</p><pre style="background-color: #fff2cc;">$00: 045A 02EE 0000 0008 0000 0210 0020 0002 EE00 0000 2020 2020 2020 2020 2020 2020
$10: 2020 2020 2020 2020 0002 0002 0004 6462 3031 2E32 3061 5051 4920 4944 4520 4469
$20: 736B 4F6E 4D6F 6475 6C65 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 0001
$30: 0000 0200 0000 0200 0000 0001 02EE 0008 0020 EE00 0002 0100 EE00 0002 0000 0000
$40: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
...
$F0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
model name = PQI IDE DiskOnModule
serial number =
firmware revision = db01.20a
fixed disk
ATA version = 0
LBA supported
Default capacity (sectors) = 192000
default C/H/S = 750/8/32
default capacity (sectors) = 192000
current C/H/S = 750/8/32
current capacity (sectors) = 192000
device supports PIO mode 3 or DMA mode 1 or above
</pre><p>Next reading from the slave, a <i>Seagate ST1</i> hard disk in the CF card slot, did not work. The <i>ST1</i> always reported <tt>!ready</tt>.</p><p>I thought there could be a severe problem with the pin assignment of the CF card slot, but after double checking, it was ok. Next i suspected a missing pull-up on the <tt>/CS</tt> line, which discriminates between master and slave, but these inputs <u>have</u> an internal pull-up.<br />
Then i checked the <i>ST1</i>: with the help of an USB-CF-Card adapter i attached it to my Mac and it spined up. I watched some very cool short videos which i had saved on the drive a few years ago:</p><ul><li><a href="https://www.youtube.com/watch?v=4tHAtz0g4mE">[AMV] FLCL - Deep Purple - Speed King.mpg</a></li>
<li><a href="http://www.spreeblick.com/blog/2011/05/11/beat-machine/">Beat_Machine_Spreeblick.avi</a></li>
<li><a href="https://www.youtube.com/watch?v=15I91i8RnnE">Polt.flv</a></li>
<li><a href="https://www.youtube.com/watch?v=pmfHHLfbjNQ">Radiohead - Nude (ZX Spectrum Remix).mp4</a></li>
</ul><p>Do ya know any of them?</p><p>Then i rummaged around for some Compact "Flash" cards and came up with a 256 MB and a 16 MB one (the latter one i actually don't own. Hi Axel, do you miss your 16 MB card? I just found it… <b style="background:#f99">:-)</b>)</p><p>I tested them.</p><p>And they worked:</p><pre style="background-color: #fff2cc;">$00: 848A 02B7 0000 000F 0000 0200 0030 0007 A2B0 0000 5830 3130 3220 3230 3033 3130
$10: 3237 3032 3536 3137 0002 0002 0004 5265 7620 332E 3030 4869 7461 6368 6920 5858
$20: 4D32 2E33 2E30 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 0001
$30: 0000 0200 0000 0100 0000 0001 02B7 000F 0030 A2B0 0007 0100 A2B0 0007 0000 0000
...
$F0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
model name = Hitachi XXM2.3.0
serial number = X0102 20031027025617
firmware revision = Rev 3.00
removable medium
ATA version = 0
LBA supported
Default capacity (sectors) = 500400
default C/H/S = 695/15/48
default capacity (sectors) = 500400
current C/H/S = 695/15/48
current capacity (sectors) = 500400
device supports PIO mode 3 or DMA mode 1 or above
</pre><p>and</p><pre style="background-color: #fff2cc;">$00: 848A 00F4 0000 0004 4000 0200 0020 0000 7A00 0000 3932 3130 3336 3230 3130 3938
$10: 3939 3039 3132 3831 0002 0002 0004 5631 2E30 3220 2020 4C45 5841 5220 4154 4120
$20: 464C 4153 4820 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 0001
$30: 0000 0200 0000 0200 0000 0003 00F4 0004 0020 7A00 0000 0100 7A00 0000 0000 0000
...
$70: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
$80: 0000 75D0 0075 A800 75B8 0078 0174 55F6 08F4 B800 FA08 F4F5 F0E6 B5F0 10F4 F5F0
$90: 08B8 00F5 7801 B455 E674 0001 A700 7455 01A7 90C0 5974 01F0 E4F0 90C0 2D8D E6A6
$A0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
...
$F0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
model name = LEXAR ATA FLASH
serial number = 92103620109899091281
firmware revision = V1.02
removable medium
ATA version = 0
LBA supported
Default capacity (sectors) = 31232
default C/H/S = 244/4/32
default capacity (sectors) = 31232
current C/H/S = 244/4/32
current capacity (sectors) = 31232
device supports PIO mode 3 or DMA mode 1 or above
device supports Ultra DMA
</pre><p>But the <i>ST1</i> refused to become ready. </p><p>I played around with the master/slave setting and found, that the "jumper" on the PQI module probably enforced master for the device. This had to be taken into account when changing the master/slave jumper on the IDE board. (I first thought it had something to do with power supply, because this is an IDE module and the IDE bus normally provides no power, but i was wrong.)</p><p>Finally i jumpered the CF card adapter as master, pulled the master "master" jumper on the PQI module, and the CF card and the PQI module still answered, with roles swapped, and, unbelievable, the <i>Seagate ST1</i> answered too! So, to make the <i>ST1</i> work, i need to set the CF card adapter – the "removable" medium – to master and the "fixed" PQI module to slave? I tried with an empty CF card slot and the PQI module still answered - as slave. Is this IDE standard? (Actually i know very little about CF, IDE and so on, the official documents cost money for download or membership. So i get what can be found with the help of aunt <a href="https://www.google.com/">Google</a>.)</p><pre style="background-color: #fff2cc;">$00: 848A 12ED 0000 0010 7E00 0200 003F 004A 8530 0000 2020 2020 2020 2020 2020 344D
$10: 4430 3433 4B53 2020 0003 0100 0004 332E 3034 2020 2020 5354 3632 3532 3131 4346
$20: 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 8010
$30: 0000 0B00 0000 0200 0000 0007 12ED 0010 003F 8530 004A 0100 8530 004A 0000 0407
$40: 0003 0078 0078 0078 0078 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
$50: 0000 0000 7069 500C 4000 7069 100C 4000 0007 0000 0000 4040 0000 400D 8080 0000
$60: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
...
$90: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
$A0: 814A 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
$B0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
...
$F0: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
model name = ST625211CF
serial number = 4MD043KS
firmware revision = 3.04
removable medium
ATA version = 0
command sets supported = $7069 500C
command sets enabled = $7069 100C
LBA supported
Default capacity (sectors) = 4883760
default C/H/S = 4845/16/63
default capacity (sectors) = 4883760
current C/H/S = 4845/16/63
current capacity (sectors) = 4883760
device supports PIO mode 3 or DMA mode 1 or above
device supports Ultra DMA
max sectors per R/W MULTIPLE = 16
CFA power mode = 33098
</pre><p>Data transfer to and from the IDE disks is not really fast with a Z80 processor, the best what i can get is:</p><pre style="background-color: #fff2cc;">ld c,k1_wr_data
...
; send 1 word / 2 bytes in a loop
; or unroll as long as you like
ld e,(hl++)
ld a,(hl++)
out (k1_wr_hi),a ; store byte in the high-byte register
out (c),e ; send 1 word / 2 bytes to the device
</pre> <br />
<p>This takes 25 cc per byte, or, if <tt>inc hl</tt> can be replaced with <tt>inc l</tt> only, 21 cc; plus loop and setup overhead. The system has a clock frequency of 6 MHz, which means i can transfer 32 kB (the whole RAM) in 32k * 25 cc = 819200 cc or, at 6 MHz, in 1/7 sec. Ok, the CPU is slow, but the RAM is small as well. <b stale="background:#6f6">:-)</b></p><p>A single sector can be transferred in 512 * 25 cc = 12800 cc or, at 6 MHz, in 1/450 sec. This is also very fine because this means, that i can disable interrupts for a whole sector i/o without losing timer and SIO interrupts, as the timer interrupt is at 100 Hz currently. I could also increase the timer frequency to 300 or 400 Hz to allow a SIO speed of up to 38.4 kBaud, if i desired, but CPU time consumption will go up as well and with 100 Hz it's already around 2% with an idle SIO. And with very intelligent use of INI or OUTI a few cycles for at least one IN or OUT could be saved.</p><p>It should be noted that the CF cards can be operated in a byte-wide mode. Then <tt>INIR</tt> and <tt>OTIR</tt> should be usable and one byte transferred in 16 cc.</p><h3>Conclusion</h3><p>All boards work and now everything left to do is software.</p><p><i>p.s.: Still not yet written to the IDE devices. Surprise ahead? (<span style="color:#c90">Shiver…</span>)</i></p>Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-42670244983217535712016-04-15T23:19:00.000+02:002016-04-16T10:29:46.197+02:00sdcc, crc and queues<p>Hello, </p><p>this week i was busy working on my Z80 project. Though it always looks like moving in small circles, i made some progress. </p><h3>In this post:</h3><ul><li>sdcc created broken code</li>
<li>Stager Electrics' programmer failed to program an eeprom</li>
<li>There is crc-16, crc-16 and crc-16</li>
<li>Stager Electrics' programmer failed to program an eeprom</li>
<li>Simple design of queues and how long can it take to spot an error</li>
<li>Stager Electrics' programmer failed to program an eeprom</li>
<li>sdcc could produce really fast code. could…</li>
</ul><h3>Stager Electrics</h3><p>The code to detect whether i'm running on an e- or eeprom also write protects the eeprom (called SDP = software data protection) so that it cannot be overwritten when the program crashes. For that you just write certain bytes into certain addresses. Next i wrote a test message into the eeprom. This is done by writing the SDP sequence and then the bytes to program. Crashed at first as the destination buffer was calculated too small <b style="background-color: yellow;">`:-)</b> but worked on the second try. </p><p>Next i tried to overwrite an eeprom with the Stager Electrics programmer. Off course this did not work. It took <b>11 minutes</b> to write the eeprom, and after that verify failed. The programmer knows the eeprom by name and manufacturer but cannot deactivate software data protection in the eeprom. And it can't erase the device as a whole. Luckily i have more than one of these eeproms. </p><p>In a later iteration of the rom i added code which, before doing anything else, tests whether an eeprom is inserted in the ram socket (you remember: they are pin-compatible); And if so, it disables software data protection and happily bails out with a blink code. Even later i added an option to disable SDP in the current eeprom. Now that Stager thing can program the eeproms again. </p><h3>sdcc</h3><p>I probably spent one full day (after work) on tracking down a not so reproducible crash when trying to read from the i2c eeprom on the SIO board. Finally i could prove it's an error in the C compiler. In a <tt>__critical</tt> function, which means that it is executed with interrupts disabled, on entry the state of the interrupt enable flip flop is pushed on the stack so the interrupts can be re-enable or not re-enabled on return. The generated code ignored this additional word on the stack and read everything from wrong local variables. By chance the address of the destination buffer was falsely taken from the i2c eeprom reading start address, which was 0, and so reading the eeprom overwrote ram from address 0x0000 onwards. Clearly not a good idea. </p><h3>Stager Electrics</h3><p>I forgot to disable SDP in the eeprom and had to add another 11 minutes after eeprom verification failed… </p><h3>crc-16</h3><p>I want to download new rom images to the Z80 system so that the system can reprogram itself, which takes 5 seconds (at most) and not 11 minutes. The current speed on the serial port is 9600 Baud, which means 960 bytes can be transmitted per second which means after roughly 17 seconds 16 kB are transmitted (which is the current rom size) or at most 34 seconds to overwrite the whole 32 kB of the eeprom. For the "protocol" i decided after some pros and cons to just wrap the rom image with a 2-byte start and stop prefix/postfix and to add a crc checksum for error detection. </p><p>I already have a CCITT crc-16 implementation in C at hand and googled for a Z80 version which was quickly found. Then i did some tests to compare the result and found ... nothing in common. </p><p style="color: blue;">Ok, there are crc-16 and crc-16 and crc-16 and they are all different. </p><p>Let's look at the c implementation: </p><pre style="background-color: #fff2cc;">uint crc16_ccitt( uint8 const* q, uint count, uint crc )
{
while(count--)
{
for( uint c = 0x0100/*stopper*/ + *q++; c>1; c >>= 1 )
{
crc = (crc^c) & 1 ? (crc >> 1) ^ 0x8408 : (crc >> 1);
}
}
return crc;
}
</pre><p>And the Z80 version converted to a c function for easy understanding: </p><pre style="background-color: #fff2cc;">uint crc16_z80( uint8 const* q, uint count, uint hl )
{
while(count--)
{
uint8 b;
hl ^= *q++ << 8;
for(b=0; b<8; b++)
{
if((signed int)hl < 0) hl = (hl<<1) ^ 0x1021;
else hl = (hl<<1);
}
}
return hl;
}
</pre><p>First chance to make a difference is the input value for the crc. This must be <b>0xffff</b> for the CCITT version and then the function may be called repeatedly to update the CRC as bytes arrive. Off course i called them both with the same starting value. Check. <b style="color: green;">✓</b> </p><p>Next you see that both functions use different polynomials: <b>0x8408</b> and <b>0x1021</b>. Off course they must be the same to produce the same result, and they _ARE_ the same: The c function shifts bits from left to right, the z80 version from right to left, so they just work bit-reversed. Check. <b style="color: green;">✓</b> </p><p>Ok, they work bit-reversed when compared to each other. So the result must be bit reversed. But even when reverting one result the CRCs are completely different. </p><p style="color: blue;">So what's the difference? </p><p>The bytes read from the data buffer must be bit reversed as well (in any one function) to make all data bit-reversed, then the result (of any one function) can be bit reversed and then they will be actually identical! </p><p>The fully bit-reversed version of the first function looked like this: </p><pre style="background-color: #fff2cc;">#define R1(N) ((N<<7)&0x80)+((N<<5)&0x40)+((N<<3)&0x20)+((N<<1)&0x10) + \
((N>>7)&0x01)+((N>>5)&0x02)+((N>>3)&0x04)+((N>>1)&0x08)
#define R4(N) R1(N),R1((N+1)),R1((N+2)),R1((N+3))
#define R16(N) R4(N),R4((N+4)),R4((N+8)),R4((N+12))
#define R64(N) R16(N),R16((N+16)),R16((N+32)),R16((N+48))
uint8 rev[256] = { R64(0), R64(0x40), R64(0x80), R64(0xC0) };
uint16 crc16r( uint8 const* q, uint count )
{
uint crc = 0xffff;
while(count--)
{
for( uint c = 0x0100 + rev[*q++]; c>1; c >>= 1 )
{
crc = (crc^c) & 1 ? (crc >> 1) ^ 0x8408 : (crc >> 1);
}
}
return rev[crc>>8] + (rev[crc&0xff]<<8);
}
</pre><p>Now i have a C and a Z80 implementation for a CRC-16 checksum which work identical. <b style="background-color: #afa;">`:-)</b> </p><p><i>Note: To calculate the CCITT CRC-16 checksum with the first function, calculation must be started with CRC = 0xFFFF and the final CRC must be complemented. Then all sources say that you must swap the low and high byte. But that's not true, or, that's not the point. Whether you must swap the bytes depends on how you read the CRC from the data stream and what byte order your computer uses. I believe that the low byte is transmitted first. (to be tested somehow & somewhen…)</i></p><p><i>The Z80 version calculates the CRC-16 used in the XMODEM file transmission protocol. Here the CRC must be initialized with 0x0000, the final CRC must not be complemented and the high byte is sent first.</i></p><h3>Stager Electrics</h3><p>I forgot to disable SDP in the eeprom and after programming eeprom verification failed and i thought it was defective now… </p><h3>Queues</h3><p>I use a nice design for queues (in the sio implementation) which avoids the need for locks (or mutexes). </p><pre style="background-color: #fff2cc;">#define busize 64 // 2^N
#define bumask busize-1
uint8 bu[busize];
uint ri; // read_index
uint wi; // write_index
</pre><p>Normally writing to a queue works like this: <br />
<i>(I'll only describe writing, reading is similar.)</i> </p><pre style="background-color: #fff2cc;">bu[wi++] = mybyte;
wi &= bumask;
</pre><p style="color: blue;">Drawback: </p><p>You cannot distinguish between a full and an empty buffer, so you fill it up to at most busize-1 bytes. </p><p>This can be helped: </p><pre style="background-color: #fff2cc;">bu[wi++ & bumask];
</pre><p>Now the buffer is empty if <tt>wi==ri</tt> and full if <tt>(wi-ri)==busize</tt>.<br />
<tt>ri</tt> and <tt>wi</tt> will at some time overflow but the integer arithmetics remain valid. </p><p>As not obvious, this implementation needs locking: wi is incremented before the byte is written and the buffer reader could interrupt between <tt>wi++</tt> and writing the byte into the buffer, and read the not yet written byte. But this can be remedied like this: </p><pre style="background-color: #fff2cc;">bu[wi & bumask]; wi++;
</pre><p>Now the byte is stored first and then the write pointer is incremented, "releasing the semaphore". </p><h3>how long can it take to spot an error?</h3><p>These are the data structs containing the data for each channel: </p><pre style="background-color: #fff2cc;">struct SioData
{
bool hw_handshake;
uint8 sw_handshake; // bit.0: enabled
uint8 clk_handshake; // bit.0: emit TX clock
uint8 device; // select mask
uint8 channel; // 0 = channel A; 1 = channel B
uint8 baudrate; // baudrate / 2400
uint8 ibuwi; // input buffer write index
uint8 iburi; // input buffer read index
uint8 obuwi; // output buffer write index
uint8 oburi; // output buffer read index
uint8 ibu[ibusz]; // input buffer
uint8 obu[obusz]; // output buffer
};
</pre><p>These are two actual implementations in in my sio source: </p><pre style="background-color: #fff2cc;">uint sio_avail_in(struct SioData* channel)
{
return channel->ibuwi - channel->iburi;
}
uint sio_avail_out(struct SioData* channel)
{
return obusz - (channel->obuwi - channel->oburi);
}
</pre><p>Nice! <b style="background-color: yellow;">:-)</b> </p><p>And both wrong. <b style="background-color: #faa;">:-?</b> </p><p>When i tested transmission of data from my Mac to the Z80 system, i only got transmission errors. The Z80 system received all data when CoolTerm was at 50 .. 80%. I suspected CoolTerm. I suspected the USB-RS232 driver software. (Which actually _IS_ pretty buggy.) I suspected sdcc. I scrutinized the Z80 assembler interrupt routine. I examined the test routine itself. (A common place. Actually i started here… <b style="background-color: yellow;">;-)</b>) I examined <tt>gets(…)</tt>, which receives all available data into a buffer and which is written in C. I examined <tt>sio_avail_in(…)</tt>. Not only once … My source and what sdcc compiled. And <tt>sio_avail_in(…)</tt> was buggy. But it took me hours to see the error. Do you spot the error? C'mon, it's only one line of code. A single subtraction of two values… </p><h3>sdcc could produce really fast code. could…</h3><p>I have written several versions of the CRC routine, two (similar versions) in Z80 and some in C. I timed them and i got interesting results. </p><pre>CRC-16 ZMODEM of rom (asm1) dt=1180 ms
CRC-16 ZMODEM of rom (asm2) dt=1430 ms
CRC-16 CCITT of rom (c) dt=9500 ms
CRC-16 ZMODEM of rom (c) dt=3020 ms
</pre><p>The C functions to calculate the XMODEM CRC is much faster than the function to calculate the CCITT CRC, though they both contain equivalent source. </p><p style="color: blue;">That was with sdcc 3.4. </p><p>Due to the <tt>__critical</tt> error mentioned at the beginning of this post i looked for the latest version of sdcc. I thought, if i send in a bug report they'll surely complain that it's for version 3.4, which is 2 years old. </p><p>So i looked for the latest version: Version 3.5, which is 10 months old. (sigh). </p><p>It still had the <tt>__critical</tt> bug but i found the bug tracker and an entry for this bug: Fixed in 9'2015. Version 3.5 is from 6'2015. <i>sigh…</i> </p><p>So i searched and found the beta versions (more like nightly builds) and the latest OSX version was 13 minutes old. <b style="background-color: yellow;">:-)</b> It no longer has the <tt>__critical</tt> bug (tested), needs some other includes (copied) and produces slightly larger code. And i ran the CRC test again: (rom now slightly bigger) </p><pre>CRC-16 ZMODEM of rom (asm1) dt=1200 ms
CRC-16 ZMODEM of rom (c) dt=8500 ms
</pre><p>The C routine is now nearly 3 times slower? </p><p>So i reverted to sdcc 3.4 and reinstalled my workaround for the <tt>__critical</tt> bug… </p><p></p><p> ... Kio ! </p><p>p.s.: @ Google: The editor is crap. could you please fix it? </p><h3 style="background-color: yellow;">---- SPOILER WARNING ----</h3><p style="background-color: black;">p.p.s.: the read and write indexes in the sio struct are (unsigned) bytes. <br />
When they are subtracted in <tt>sio_avail_*(…)</tt> they are extended to 2-byte values.<br />
If the write index has already overflowed and the read index not, then the difference is not limited to 8 bits as expected but the high byte of the result is 0xFF. </p><br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-23370446036546337252016-04-10T20:13:00.000+02:002016-04-11T16:41:05.293+02:00Z80 Microcomputer with SRAM and K1-BusAfter suspending the project for a while, i'm now back to it. This is an update to the current state.<br />
<br />
<h3>
Hardware</h3>
There were some errors in the circuit, which i could fix. The V2.0 Eagle file on <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%20Z80%20CPU%20board%20with%20SRAM/" target="_blank">my website</a> already contains these fixes.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipNu1irZbElJ46KtnaKJDekgg8ZWJSem2kdrzPavss83DjKRK_qWO8e7BeyQpQ3FDZZLsrbXKEQWoLxuyHLCYQc8ApX9jbDvP9MYLnul1SZSNFgwnbPHXy0PrChoh7L4FK8HYgj6VD7rw/s1600/2016-04-09+board+read+side+fix+%25232.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipNu1irZbElJ46KtnaKJDekgg8ZWJSem2kdrzPavss83DjKRK_qWO8e7BeyQpQ3FDZZLsrbXKEQWoLxuyHLCYQc8ApX9jbDvP9MYLnul1SZSNFgwnbPHXy0PrChoh7L4FK8HYgj6VD7rw/s320/2016-04-09+board+read+side+fix+%25232.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">2016-04-08 fixed board</td></tr>
</tbody></table>
<b>Blue wires: </b>A6 and A7 are used (beside A5) to select the target of an i/o operation. One of these is the access to the i2c bus on the k1 bus, where also my debugging LEDs are attached. When i2c is selected in an i/o operation, then A6 and A7 are used to set the i2c data and clock lines. – But wait, A6/7 are used to select i2c operation AND to select something within the i2c operation? Merde… So i rerouted the i2c lines to use A3 and A4 instead.<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhoGB4JN5-2HvNfNBxY41_7tFGububdIbeIfvssXyQ3qyVapkOjiwmiL3RH6ylbC2zwpTpCgggTn0Bu-wrZVkWW5_zIPLIU545E5p6E89K-zW5pcIRbcDqPuxob-Sqp4SDacYDlOSfANU/s1600/Bildschirmfoto+2016-04-10+um+17.44.21.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhoGB4JN5-2HvNfNBxY41_7tFGububdIbeIfvssXyQ3qyVapkOjiwmiL3RH6ylbC2zwpTpCgggTn0Bu-wrZVkWW5_zIPLIU545E5p6E89K-zW5pcIRbcDqPuxob-Sqp4SDacYDlOSfANU/s320/Bildschirmfoto+2016-04-10+um+17.44.21.png" width="320" /></a><b>Yellow wires:</b> As you can see by a look at the ram/rom address decoder in the last post, ram and rom selection is exchanged. First i fixed this by inserting eeprom and ram into each other's socket, which is possible with the eeprom, but not with the eprom.<br />
For my (e)eproms i use a programmer from Stager Electric, Shenzhen, China. If you ever see something made by Stager Electric: run as fast as you can! It takes ~11 minutes to write a few bytes into an eeprom. The application has an option to "disinterest blanck" and eventually in the next version (which i never saw) it even worked… So it always programs full 32k and, since even this can be done in less than 32768/64*10ms = 5.12 seconds, and it actually takes 11 minutes, which is more than 100 times longer, i presume the eeprom is programmed byte by byte, making sure that it's write endurance of 10000 is in reachable distance... So i wanted to use eproms and fixed the circuit. Programming eproms is even faster as well.<br />
<b>Component side: </b>A minor glitch is on the component side: I have carefully engraved "E" and "EE" for the eprom/eeprom selection pin header into the copper layer, and again, did it wrong: exchanged, as always…<br />
<br />
<h3>
Software</h3>
I was playing a little with my c-style compiler to add a Z80 target, and found: the Z80 is really bad suited to implement anything a compiler might try to create. Too few registers which frequently have special features. Deploying the second register set is near impossible. Using index registers is painfully slow. (you already knew that) Local variables on the stack are a pain to access.<br />
<br />
Basically you have the choice to generate real machine code, which is not only slow but bloated as well, and some kind of Forth-style virtual code, which is short but even slower.<br />
<br />
I finally came to the "fastest possible Forth-style" code model, which i will pursue later: It uses a jump table and opcodes which are 1-byte index into this table; which is faster (and shorter) than using 2-byte addresses in the program as Forth implementations typically do. Drawback: i need the table and the table can contain only ~256/3 entries. So there must be "prefix" opcodes which then are slower.<br />
<br />
The jump table looks like this:<br />
<br />
<pre style="font-family: "courier new" , "courier" , monospace; font-size: small; line-height: 100%;">vector: macro $NAME
$NAME:: equ $ - vtable
jp _$NAME
endm
; ------------------------------------
vector RESET ;( -- )
vector SHELL ;( -- )
vector NATIVE ;( -- )
vector ABORT ;( uint -- )
vector MODs ;( n n -- n )
vector DIVs ;( n n -- n )
vector MODu ;( n n -- n )
vector DIVu ;( n n -- n )
vector MUL ;( n n -- n )
vector JP1 ;( n $dest -- )
vector JP0 ;( n $dest -- )
vector JP ;( $dest -- )
</pre>
<br />
<div>
<span style="font-family: inherit;">and so on. You see, each entry is a JP opcode (by virtue of the macro), but "inline" code in the table is sometimes possible as well, e.g. if a variant of an opcode just needs a short mockup of the arguments, it's code can be put directly in the table before the other opcode, where it simply runs into. It's a trade-off of used space and gained speed.</span></div>
<br />
A typical "word" looks like this:<br />
<br />
<pre style="font-family: "courier new" , "courier" , monospace; font-size: small; line-height: 100%;">_SUB: ;( n1 n2 -- n )
pop hl ; hl=n1
and a ; de=n2
sbc hl,de ; hl=result
ex de,hl ; de=result
next
</pre>
<br />
<div>
<span style="font-family: inherit;">where <b>next</b> is a macro:</span></div>
<br />
<pre style="font-family: "courier new" , "courier" , monospace; font-size: small; line-height: 100%;">; fetch next virtual opcode and jump to handler
;
next: MACRO
ld h,hi(vtable)
ld a,(bc)
inc bc
ld l,a
jp hl
ENDM
</pre>
<br />
<div>
An alternative is to jump to any implementation of macro <b>next</b>, which is slightly slower (10 cc for the jump) but also shorter (just 3 bytes). If it can be done in a relative jump, then it's even shorter (2 bytes) and even slower as well…</div>
<br />
<div>
<span style="font-family: inherit;">As you can see i use register pair </span><b><span style="font-family: "courier new" , "courier" , monospace;">BC</span></b><span style="font-family: inherit;"> for the virtual program counter and </span><b><span style="font-family: "courier new" , "courier" , monospace;">DE</span></b><span style="font-family: inherit;"> as result register, which frees </span><b><span style="font-family: "courier new" , "courier" , monospace;">HL</span></b><span style="font-family: inherit;"> so that machine coded sub routines can pop the return address into </span><b><span style="font-family: "courier new" , "courier" , monospace;">HL</span></b><span style="font-family: inherit;">, do some work, e.g. pop arguments, and finally return via </span><b><span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">JP HL</span></b><span style="font-family: inherit;">, which is not possible if you use </span><b><span style="font-family: "courier new" , "courier" , monospace;">HL</span></b><span style="font-family: inherit;"> as result register.</span></div>
<div style="font-family: inherit;">
<br /></div>
<div style="font-family: inherit;">
<span style="font-family: inherit;">If an opcode implementation does not modify the </span><b><span style="font-family: "courier new" , "courier" , monospace;">h</span></b><span style="font-family: inherit;"> register, then it does not need to reload </span><b><span style="font-family: "courier new" , "courier" , monospace;">h</span></b><span style="font-family: inherit;"> with the high byte of the vtable address. There are actually some (few) opcodes which can exploit this additional speed boost. :-)</span></div>
<div style="font-family: inherit;">
<br /></div>
<div style="font-family: inherit;">
As you can see, the interpreter reads just one byte from the program and jumps into the vtable which contains jumps to the actual implementation of the virtual opcodes. This is faster than reading 2 bytes from the program, the program is shorter, but i need the tables and implementations for all opcodes.</div>
<div style="font-family: inherit;">
<br /></div>
<div style="font-family: inherit;">
The alternative i'm currently working with – because the Z80 backend of my compiler is not yet completed – is <b>sdcc</b>, the "Small Devices C Compiler", which has a Z80 backend. I can really tell that the generated code is bloated, and sometimes suboptimal, the syntax of the generated code is "unusual" and sometimes the compiler even crashes for me. Especially when i use the "<<" operator.</div>
<div style="font-family: inherit;">
<br /></div>
<div style="font-family: inherit;">
Here an example of what <b>sdcc</b> generates:</div>
<br />
<pre style="font-family: "courier new" , "courier" , monospace; font-size: small; line-height: 100%;">;/Firmware-Sdcc/sio.c:394: if(this->clk_handshake)
8520: DD7EFE ld a,-2 (ix)
8523: DD77FB ld -5 (ix),a
8526: DD7EFF ld a,-1 (ix)
8529: DD77FC ld -4 (ix),a
852C: DD6EFB ld l,-5 (ix)
852F: DD66FC ld h,-4 (ix)
8532: 23 inc hl
8533: 23 inc hl
8534: 6E ld l,(hl)
8535: 7D ld a,l
8536: B7 or a, a
8537: 2814 jr Z,00106$
</pre>
<br />
<div>
<span style="font-family: inherit;">The first line (the comment) is the compiled source line. As you can see the compiled code reads a word from </span><b><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">(ix-2)</span></b><span style="font-family: inherit;">, which seems to be 'this' ( a valid variable name in C </span><b style="background-color: yellow; font-family: inherit;">;-)</b><span style="font-family: inherit;"> ) and stores it at </span><b><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">(ix-5)</span></b><span style="font-family: inherit;"> which seems to be a scratch cell and immediately reads it back into </span><b><span style="font-family: "courier new" , "courier" , monospace;">HL</span></b><span style="font-family: inherit;">. Then it reads the desired value into </span><b><span style="font-family: "courier new" , "courier" , monospace;">l</span></b><span style="font-family: inherit;"> and immediately moves it into </span><b><span style="font-family: "courier new" , "courier" , monospace;">a</span></b><span style="font-family: inherit;"> for testing. A wonder of elegance. <i>(note: the scratch value is not used anywhere later, </i></span><i><b><span style="font-family: "courier new" , "courier" , monospace;">l</span></b><span style="font-family: inherit;"> is used later, but while the value in </span><b><span style="font-family: "courier new" , "courier" , monospace;">a</span></b><span style="font-family: inherit;"> is still valid too.) </span></i></div>
<br />
<h3 style="font-family: inherit;">
Current State of the Project</h3>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjURIlwCV0arMdyBGPR3Ws4oat8lQ_7ZAR0NFcmVpBVQpgQPeZXVa2tUjtxX4OKVu9kJAopX4ujiyANa8a_pLRmLMaPgKqel33Hw14rSXQyFiDuMLTvjtkICna_EN-hWPa_wg7HEtAM1vE/s1600/2016-04-09-first+words+on+the+sio.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjURIlwCV0arMdyBGPR3Ws4oat8lQ_7ZAR0NFcmVpBVQpgQPeZXVa2tUjtxX4OKVu9kJAopX4ujiyANa8a_pLRmLMaPgKqel33Hw14rSXQyFiDuMLTvjtkICna_EN-hWPa_wg7HEtAM1vE/s320/2016-04-09-first+words+on+the+sio.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Current setup</td></tr>
</tbody></table>
<div style="font-family: inherit;">
Last and this weekend i refitted all hardware, which is the CPU board, as SIO board and a (not yet tested) IDE board, as can be seen to the left, and hooked it up to a regulated power supply. Current consumption is pretty low, as it's all CMOS: only 50 to 80 mA (depending on how many LEDs are lit) for all three boards, including a 96MB IDE flash rom (hiding between the IDE and the SIO board) and a 2.5GB compact flash size hard drive (sticking out from the rear side so you can't see it as well).</div>
<div style="font-family: inherit;">
Slowly iterating from one broken software step to the next, regularly erasing and reusing my eproms and finally even testing some steps <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%20Z80%20CPU%20board%20with%20SRAM/Emulator/" target="_blank">in the emulator</a> (erm, yes, i have written an emulator for the system too, using my Z80 emulation from <a href="http://k1.spdns.de/Develop/Projects/zxsp-osx/Distributions/" target="_blank">zxsp</a> and the SIO and a LCD display emulation from my K1 CPU project) i finally got the first text message from the board. I have attached the SIO port A to a RS232-to-USB converter and use CoolTerm on my Mac to receive the messages. I stepped back to an old version of CoolTerm, as the current versions very quickly use 100% of one CPU core. </div>
<div style="font-family: inherit;">
For the SIO software i use a simplified approach: The SIO ports are polled on the system timer interrupt (which is generated by the UART as well) which is currently 100 Hz. The UART has 16 byte fifo queues, so 100 Hz is way enough for 9600 Baud. But i'll probably go up to 200 Hz for 19200 Baud at least. As sending data works, the system interrupt works as well. </div>
<div style="font-family: inherit;">
Idle CPU usage for this interrupt is approx. 2% (calculated), and will be ~4% with 200 Hz, if i don't find a better solution. On the photo above you can see that the red LED in front is lit. This LED indicates WAIT state and currently the CPU waits approx. 98% of the time. (Or 96%, as it's also sending some text through some ugly compiled c code…) So i can say, this LED works as well. <b style="background-color: yellow;">:-)</b></div>
<div style="font-family: inherit;">
Today i have tested writing of data into the eeprom. (actually only detecting whether it's an eeprom or not, but that's quite similar.) This works too. </div>
<div style="font-family: inherit;">
<br /></div>
<div style="font-family: inherit;">
Next steps: </div>
<div style="font-family: inherit;">
<ul>
<li><span style="font-family: inherit;"><strike>Actually write some bytes into the eeprom</strike> ➞ done 2016-04-11</span></li>
<li><span style="font-family: inherit;">test reading of the i2c eprom on the SIO board</span></li>
<li><span style="font-family: inherit;">test writing to the i2c eeprom</span></li>
<li><span style="font-family: inherit;">receive data from the SIO port</span></li>
<li><span style="font-family: inherit;">receive program data from the sio port and write it into eeprom.</span></li>
<li><span style="font-family: inherit;">lock away the Stager Electrics programmer. </span><b style="background-color: yellow; font-family: inherit;">;-)</b></li>
</ul>
</div>
<div style="font-family: inherit;">
Final question is: what should i do with the board? hm hm…</div>
<div style="font-family: inherit;">
<br /></div>
<div style="font-family: inherit;">
Stay tuned. </div>
<div style="font-family: inherit;">
<br />
p.s.: Today i wrote a test message into the eeprom. Off course it did not work right from the start – it crashed because the destination space was too short, and behind that in the eeprom was the sio interrupt handler which was then partly overwritten.<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcyB54ErlINijIjq8B76DLnV84i2N_1IUpeHbFq1CioKBOVXsmB0m8DKn2ExzhQKDlvQk2BtLLVYiFy0Ttr_pG0OzxCMICZoTvrFZsSl1rbfZhXpnMBNFt0RUZi3ZV9MJxnKChqRhLEHo/s1600/Bildschirmfoto+2016-04-11+um+16.35.08.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcyB54ErlINijIjq8B76DLnV84i2N_1IUpeHbFq1CioKBOVXsmB0m8DKn2ExzhQKDlvQk2BtLLVYiFy0Ttr_pG0OzxCMICZoTvrFZsSl1rbfZhXpnMBNFt0RUZi3ZV9MJxnKChqRhLEHo/s400/Bildschirmfoto+2016-04-11+um+16.35.08.png" /></a>I also tried to overwrite the eeprom with the Stager Electrics programmer, – which could not overwrite it. It took 11 minutes to write, and after that verify failed. I had expected this: Off course the programmer cannot deactivate software data protection in the eeprom. And it can't erase the device as a whole. Luckily i have more than one of these eeproms. And i already have a plan to make them writable again (else they'd be nice ceramic bricks): I can insert them into the ram socket and write a short eprom which does the job…<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-16345332250215839182014-08-15T12:52:00.003+02:002014-08-15T13:22:53.276+02:0068008 SRAM Microcomputer - Circuit Description V1.1While waiting for the <a href="http://kios-hardware-projects.blogspot.de/2014/08/z80-microcomputer-with-sram-and-k1-bus.html">Z80 project</a> for co-production, the 68008 board circuit has evolved. A severe bug has been removed (connecting one input of a NAND gate to ground doesn't transform it into an inverter) and a lot of timings have been scrutinized by hand, resulting in some modifications; e.g. only using address lines to select the strobe signal for the K1-bus strobe decoder or swapping /CE and /OE of the EPROM. This will be covered in another article. <br />
<br />
This post is about the logic of the circuit. It is very simple and covered in great detail, so i hope it's possible to really understand how the board works. The <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%2068008%20CPU%20board%20with%20SRAM/">project web page</a> contains some additional material and eventually reading the <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%2068008%20CPU%20board%20with%20SRAM/Data%20sheets/MC68000UM.pdf" target="_blank">68000 data sheet</a> will provide deeper insight.<br />
<br />
This is a simple 68008 CPU board for the K1-bus. It uses a 681000-70 128kB SRAM and one 27C010 128kB EPROM or one 27C512 64kB EPROM or similar. The board does not contain any i/o circuitry except for an unbuffered K1-bus. Even a system timer must be provided this way. <br />
<br />
<h3>Main Circuit</h3><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguhnF5wk2aWH9L41gfCzBBOAT2_Rl5XRBrJd8UrPNBKkxowfUz5GkgiTo5oQpC_jI5a2aobd2VkxxdRVqdOHoI2Q8HA7wmgAsFdh6yksvGLnwhUuLdmRk9OSiygCki1huXsraFkp62kGA/s1600/main+circuit.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguhnF5wk2aWH9L41gfCzBBOAT2_Rl5XRBrJd8UrPNBKkxowfUz5GkgiTo5oQpC_jI5a2aobd2VkxxdRVqdOHoI2Q8HA7wmgAsFdh6yksvGLnwhUuLdmRk9OSiygCki1huXsraFkp62kGA/s1600/main+circuit.png" height="288" width="640" /></a><br />
<i>Main Circuit with CPU, RAM and ROM</i><br />
<br />
The connection of RAM and ROM is very straight forward. Data bus lines and address bus lines are connected 1:1. Only two standard logic chips are used to interface the control signals: one 74HCT00 quad NAND and one 74HCT139 dual 2-to-4 decoder. <br />
<br />
CPU control outputs used are <b><tt>/AS</tt></b> (controlling all bus cycles) and <b><tt>/WR</tt></b> (discriminating between read and write cycles). CPU control inputs used are <b><tt>/DTACK</tt></b> (terminate a bus cycle), <b><tt>/VPA</tt></b> (terminate a slow bus cycle) and <b><tt>/IPL1</tt></b> (interrupt request).<br />
<br />
<b>Let's start with the signals provided and received by the 68008 CPU:</b><br />
<br />
<b><tt>CLK</tt></b>: a clock signal of 10 MHz is generated by a DIL clock generator.<br />
<br />
<b><tt>FC0</tt></b> to <b><tt>FC3</tt></b>: These outputs provide information about each bus cycle: Whether it's program or data and whether it's user mode or supervisor and whether it's an interrupt acknowledge cycle. I was thinking of using this to page-in ROM at address 0x000000 after reset but found it did not save me components and would make software more complicated. <span style="color: red;">So these outputs are not used.</span><br />
<br />
<b><tt>/BERR</tt></b>: signals a bus error to the CPU. <span style="color: red;">Not used on this board.</span> There will never be a bus error detected. All bus cycles terminate with <b><tt>/DTACK</tt></b> or <b><tt>/VPA</tt></b>.<br />
<br />
<b><tt>/BR</tt></b> and <b><tt>/BG</tt></b>: Used for multi bus master control. <span style="color: red;">Not used on this board.</span> There is only one bus master: the CPU.<br />
<br />
<b><tt>/RESET</tt></b> and <b><tt>/HALT</tt></b>: After power-up the CPU must be reset for 0.1 seconds (really!) by pulling these lines low. Both pins are outputs as well: <b><tt>/RESET</tt></b> can be asserted by software and will in return activate <b><tt>/HALT</tt></b>: this will halt the CPU <u>after</u> the current bus cycle, by when <b><tt>/RESET</tt></b> is already released again thus it should not cause problems to the CPU. Or <b><tt>/HALT</tt></b> can be asserted and will reset the CPU. <b><tt>/HALT</tt></b> is asserted if double bus errors are detected (and evtl. other conditions) and can eventually never happen with this board. To be tested when built :-) This signal is directly connected to the K1-bus <b><tt>/RESET</tt></b> line.<br />
<br />
<b><tt>/AS</tt></b>: During a bus cycle <b><tt>/AS</tt></b> is activated while the address is valid. <span style="color: #00bb00;">Basically <b><tt>/AS</tt></b> going low starts a bus cycle and <b><tt>/AS</tt></b> going high terminates it.</span><br />
<br />
<b><tt>/DS</tt></b> is similar to <b><tt>/AS</tt></b> but in write cycles it is asserted slightly later than <b><tt>/AS</tt></b>. I thought that it was not asserted at all in 6800 cycles, because the signal is not shown in the 6800 timing chart, but it is, as can be seen in the autovector timing chart. <span style="color: red;">This signal is not used.</span><br />
<br />
<b><tt>/WR</tt></b> indicates that this bus cycle is a write cycle. The opposite signal <b><tt>/RD</tt></b> does not exist and is generated by an inverter.<br />
<br />
<b><tt>/DTACK</tt></b>: Data Acknowledge is asserted by external circuitry to tell the CPU that it can finish the current bus cycle. It is possible to keep this signal low all the time so that the CPU will run without wait cycles. (Though the timing charts all tell you that this signal has to go up and down.) On this board <b><tt>/DTACK</tt></b> is asserted all the time except if <b><tt>/WAIT</tt></b> on the K1-bus is activated or a slow bus cycle is performed which will be terminated by <b><tt>/VPA</tt></b>.<br />
<br />
<b><tt>/VPA</tt></b> is connected to a signal called <b><tt>/SLOW_IO</tt></b>: A bus cycle of the 68008 can be terminated normally in two ways: by <b><tt>/DTACK</tt></b> or by <b><tt>/VPA</tt></b>. <b><tt>/VPA</tt></b> means "valid peripheral address" and is used to interface old (very old!) 6800 peripherals. The 68008 then does an extremely slow bus cycle. I use this to do very slow i/o cycles on the K1-bus. <b><tt>/VPA</tt></b> has a second meaning: If an interrupt acknowledge cycle is terminated with <b><tt>/VPA</tt></b>, then the CPU does not read the interrupt vector from the data bus but generates an 'autovector' internally. This board does not use <b><tt>/VPA</tt></b> for interrupt acknowledge cycles. Instead it uses vectored interrupts and uses <b><tt>/DTACK</tt></b> to terminate interrupt acknowledge cycles.<br />
<br />
<b><tt>IPL0/2</tt></b> and <b><tt>IPL1</tt></b>: Interrupt inputs. The 68000 has 3 interrupt lines, the 68008 has only 2 due to pin shortage in the dip package and connects both IPL0 and IPL2 to one pin. Pulling low any combination of these lines forces an interrupt in the 68008. Pulling low all interrupt lines generates a non-maskable interrupt, pulling low less lines results in an interrupt of level 1 to 6. In the 68008 normal interrupts of level 2 (IPL1) and 5 (IPL0/2) can be generated. This board uses only interrupt <b><tt>IPL1</tt></b>, which is directly connected to the K1-bus interrupt line.<br />
<br />
<b>The Control Signals of the RAM and ROM:</b><br />
<br />
<b><tt>/CE</tt></b>: This enables the memory chip. While enabled, it can be read or written. The RAM also has a positive <b><tt>CE2</tt></b> input, but this is not used. <b><tt>/CE</tt></b> is enabled by a 2-to-4 address decoder. See below.<br />
<br />
<b><tt>/OE</tt></b>: If the memory chip is enabled, asserting <b><tt>/OE</tt></b> enables it's output drivers and the currently addressed byte is put on the data bus, where it can be read by the CPU. <b><tt>/OE</tt></b> is connected to the inverted <b><tt>/WR</tt></b> signal of the CPU: so at any time either <b><tt>/OE</tt></b> or <b><tt>/WR</tt></b> is enabled.<br />
<br />
<b><tt>/WE</tt></b>: The RAM can also be written: if <b><tt>/WE</tt></b> is asserted while the RAM is enabled, then it will read the byte from the data bus and write it into the currently addressed memory cell. <b><tt>/WE</tt></b> is connected directly to the CPU's <b><tt>/WR</tt></b> output.<br />
<br />
<b><tt>/CE</tt></b> and <b><tt>/OE</tt></b> of the EPROM are not connected as expected but swapped: the result is the same – the EPROM puts data on the data bus if both signals are enabled – but memory access after <b><tt>/CE</tt></b> is much slower than after <b><tt>/OE</tt></b> and enabling the chip with <b><tt>/CE</tt></b> would always require one wait state, at least if i use one of my (well stocked) 27C512-250 EPROMs with 250 nano seconds access time from <b><tt>/CE</tt></b>. But the EPROM's access time from <b><tt>/OE</tt></b> is only 100 ns, and therefore i connect <b><tt>/OE</tt></b> to the timing critical output of the 2-to-4 address decoder and <b><tt>/CE</tt></b> to the less timing critical <b><tt>/RD</tt></b> signal and can access the EPROM with no wait cycles.<br />
<br />
<h3>Glue Logics</h3><br />
Only two standard logic chips are used to interface the control signals: one 74HCT00 quad NAND and one 74HCT139 dual 2-to-4 decoder.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoGZtHinvz9GaVVWiquyUrjIsifnvdNMfNp4ROd2c2eQw6sBEqbgZXB51ah10hpklWtkfu1mMBBNcuvdoYsfIjF8IMlZuHITcl-Tm9B8ApBzBSsNTv1y4D65DG8RIUnPSpFcK4_PY8WmI/s1600/74HCT00.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoGZtHinvz9GaVVWiquyUrjIsifnvdNMfNp4ROd2c2eQw6sBEqbgZXB51ah10hpklWtkfu1mMBBNcuvdoYsfIjF8IMlZuHITcl-Tm9B8ApBzBSsNTv1y4D65DG8RIUnPSpFcK4_PY8WmI/s1600/74HCT00.png" /></a></div><b>Bringing it all together</b><br />
<br />
<span style="color: #00bb00;"><b>The 74HCT00 quad NAND</b></span> provides one NAND, one inverter and one flip flop, as can be seen to the left.<br />
<br />
<span style="color: #00bb00;">The first gate</span> generates <b><tt>/DTACK</tt></b> to terminate most bus cycles. <b><tt>/DTACK</tt></b> is permanently low except if <b><tt>/SLOW_IO</tt></b> or <b><tt>/K1_WAIT</tt></b> is low. <b><tt>/K1_WAIT</tt></b> originates from the K1-bus and <b><tt>/SLOW_IO</tt></b> is activated when access to a special address range is decoded.<br />
<br />
<span style="color: #00bb00;">The 2nd gate</span> is used to invert the <b><tt>/WR</tt></b> signal of the CPU to generate the <b><tt>/RD</tt></b> signal required by the RAM and ROM.<br />
<br />
<span style="color: #00bb00;">Gate 3 and 4</span> construct a flip flop. After reset the CPU reads reset vectors from address 0x000000 which can only be provided by reading from ROM. But at runtime we'd like to have RAM at address 0x000000 to allow the running program to modify the vector table. To achieve this, this flip flop is set by the <b><tt>/RESET</tt></b> signal and cleared by the first access to an i/o address which activates signal <b><tt>/CLEAR_INIT</tt></b>. While set, the <b><tt>INIT</tt></b> output is used to temporarily map ROM at address 0x000000.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmZC2fvSxhJIM1AKZVBgMWyeU8LJHHX64qsSSJ_8JVaITIpuOeITAOaM1cVedP5UDsqizwuFEHaAVTP0kUmB91VJnZcCaySgDfGvwxoWSd9Cr1YNCM3XGuE6O2RqNdbPptsubMmBvT6-E/s1600/74HCT139.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmZC2fvSxhJIM1AKZVBgMWyeU8LJHHX64qsSSJ_8JVaITIpuOeITAOaM1cVedP5UDsqizwuFEHaAVTP0kUmB91VJnZcCaySgDfGvwxoWSd9Cr1YNCM3XGuE6O2RqNdbPptsubMmBvT6-E/s1600/74HCT139.png" /></a></div><span style="color: #0022ee;"><b>The two 2-to-4 decoders of the 74HCT139</b></span> are used to generate the RAM and ROM <b><tt>/CE</tt></b> signals, to clear the init_FF and to generate the <b><tt>/SLOW_IO</tt></b> signal.<br />
<br />
The 1 MB address space of the 68008 CPU is divided into 4 regions: RAM, ROM, fast i/o and slow i/o.<br />
<br />
<span style="color: #0022ee;">The first decoder</span> generates the RAM and ROM <b><tt>/CE</tt></b> signals. As explained above it actually generates <b><tt>/OE</tt></b> for the EPROM. For this it decodes the highest address lines <b><tt>A19</tt></b> and <b><tt>A18</tt></b>: <b><tt>A19</tt></b> must be low for both and <b><tt>A18</tt></b> discriminates between RAM and ROM. This results in a memory map as follows:<br />
<br />
<pre>0x000000 .. 0x03ffff max. 256kB SRAM (actual size: 128kB)
0x040000 .. 0x07ffff max. 256kB ROM (actual size: 64kB or 128kB)</pre><br />
As explained above we need ROM at address 0x000000 after reset. Therefore signal <b><tt>INIT</tt></b> from the init_FF is used to pull <b><tt>A0</tt></b> of the address decoder high, so that memory accesses in the RAM address range will activate the EPROM instead. Technically the resistor and the diode construct an OR gate.<br />
<br />
The decoder is strobed with <b><tt>/AS</tt></b> from the CPU so that there are no spikes on the outputs when the address toggles between bus cycles. This is important, so that the RAM does not erroneously write some void data into random cells and that <b><tt>/CLEAR_INIT</tt></b> is not activated too early, e.g. immediately after reset before the CPU even read the first byte of the reset vector. <br />
<br />
<b><tt>/CLEAR_INIT</tt></b> is generated when <b><tt>A19</tt></b> is high and either <b><tt>A18</tt></b> or <b><tt>INIT</tt></b> is high, and will clear the init_FF. <b><tt>A19</tt></b> high means this is an i/o address.<br />
<br />
<span style="color: #0022ee;">The second decoder</span> generates the <b><tt>/SLOW_IO</tt></b> signal, which is connected to the CPU's <b><tt>/VPA</tt></b> address input and to the first NAND gate to suppress <b><tt>/DTACK</tt></b>. If this signal is activated, the CPU will perform a very slow 6800 peripherals bus cycle. The signal is activated when <b><tt>A19</tt></b> is high and <b><tt>A14</tt></b> is low:<br />
<br />
<b><tt>A19</tt></b> must be high for any i/o access, because <b><tt>A19</tt></b> low is used for memory access, either RAM or ROM.<br />
<br />
<b><tt>A14</tt></b> is used to discriminate between fast and slow i/o cycles. If we'd use <b><tt>A18</tt></b> instead then the first decoder would have done the job. But <b><tt>A14</tt></b> is used because it is in the low word of the address.<br />
<br />
The 68000 uses 32 bit addresses but has a short addressing mode, where a 16 bit address is sign-extended to 32 bits. This saves program space and execution time, as only 2 address bytes must be read from memory.<br />
<br />
If we want to use short addressing for i/o, then all address bits from <b><tt>A15</tt></b> to <b><tt>A31</tt></b> must be the same. And as <b><tt>A19</tt></b> is high, they must all be high. (which besides means negative addresses for i/o). This makes <b><tt>A18</tt></b> unusable for this task. On the other hand we cannot use <b><tt>A14</tt></b> to discriminate between RAM and ROM as well, because that would break memory into 16 kB chunks. <b>`:-)</b><br />
<br />
Slow i/o is deliberately chosen to be activated when <b><tt>A14</tt></b> is <u>low</u>:<br />
<br />
When the CPU performs an interrupt acknowledge cycle, it puts the acknowledged interrupt level (which is always 2 on this board) on <b><tt>A1</tt></b> to <b><tt>A3</tt></b> and pulls all other address bits high. So during an interrupt acknowledge cycle <b><tt>A14</tt></b> and <b><tt>A19</tt></b> will be high and <b><tt>/SLOW_IO</tt></b>, and consequently <b><tt>/VPA</tt></b> at the CPU will not be activated and the CPU will do a fast bus cycle and will read a vector number from the data bus. This is explained in more details below.<br />
<br />
<h3>K1-Bus I/O Circuit</h3><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjLiveLC8R00mqK4VqcgYK4PIOlWzb_xYFBq5DmlzZ-PTF8GpF26dXsQvRJBLV-ToVaplEKDF4YBtNZ_d94RDU7LQtj2-tlTBuq7dIcPClRJZX4l2FYbw6uJwzp58wHWZCT2WPiuVD-gw/s1600/K1-bus+strobes.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjLiveLC8R00mqK4VqcgYK4PIOlWzb_xYFBq5DmlzZ-PTF8GpF26dXsQvRJBLV-ToVaplEKDF4YBtNZ_d94RDU7LQtj2-tlTBuq7dIcPClRJZX4l2FYbw6uJwzp58wHWZCT2WPiuVD-gw/s1600/K1-bus+strobes.png" /></a></div>This board uses a <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/">K1-bus</a> for all peripherals. This is a hobbyist-grade 16-bit peripherals bus for CMOS devices which can be used unbuffered in small systems, as is done with this CPU board. The core K1-bus uses 16 data lines (8 may be sufficient for most cards), 6 address lines (4 mandatory) and 5 control lines, aka 'strobe lines'. It has one interrupt line, a wait request line and a reset line. <br />
<br />
A unique feature of this bus is, that cards are not selected implicitly by the address in an i/o operation but must be selected beforehand instead. The address lines are only used to select registers inside the currently selected card.<br />
<br />
Another unique feature of this bus is, that cards have an assigned data line which is used as their address. This data line is selectable with a jumpers on the i/o cards. This data line is used in conjunction with 3 of the strobe signals: <b><tt>/SELECT</tt></b>, <b><tt>/RD_IRPT</tt></b> and <b><tt>/WR_IRPT</tt></b>. The other 2 strobe signals <b><tt>/WR_DATA</tt></b> and <b><tt>/RD_DATA</tt></b> control data transfer to and from the card. <span style="color: red;">This CPU board can only use data lines D0 to D6.</span><br />
<br />
As can be seen in the circuit above, there are 3 more signals used: <b><tt>/RD_I2C</tt></b> accesses an I²C bus on the K1-bus, which is used to attach I²C EEPROMs which are used to detect cards automatically and which can provide driver code. Implementing the I²C bus interface is optional but recommended. <b><tt>/RD_HI</tt></b> and <b><tt>/WR_HI</tt></b> are used to control 2 data registers which pass data from the 8 bit data bus of the 68008 CPU to the high data byte of the 16-bit K1-bus. This is optional.<br />
<br />
A <span style="color: #0022ee;">74HCT138 3-to-8 decoder</span> is used to generate all these 8 strobe signals. A strobe signal is enabled when <b><tt>A19</tt></b> is high, which on this board means an i/o access. <b><tt>A0</tt></b> to <b><tt>A2</tt></b> select which strobe signal to activate.<br />
<br />
<b><tt>/AS</tt></b> is used to control output enable as well (to strobe the decoder outputs) so that strobe signals are only generated when the address is valid. Otherwise there would be spurious spikes on the strobe lines. The exact timing is tricky, due to wide timing windows in the 68008 timing charts, which i will discuss somewhere else.<br />
<br />
There are 4 strobes for read cycles and 4 strobes for write cycles. They are assigned to the decoder so that using the CPU's <b><tt>/WR</tt></b> signal could have been used instead of <b><tt>A2</tt></b>. And originally it was. But the bus cycle timings for the 68000 are so lousy that the risk for spikes on the decoder outputs was too high and i decided to use <b><tt>A2</tt></b> instead. Now the program must take care to access i/o addresses with bit <b><tt>A2</tt></b> properly set, or there will be bus collisions when writing to a read address.<br />
<br />
The <b><tt>/RD_IRPT</tt></b> strobe is connected to output number 5 to allow vectored interrupts:<br />
<br />
The strobe signal decoder is also activated in an interrupt acknowledge cycle, because <b><tt>/AS</tt></b> is activated as in any bus cycle and <b><tt>A19</tt></b> is high. <b><tt>A1</tt></b> to <b><tt>A3</tt></b> encode the acknowledged interrupt level, which is always 2 on this board.<br />
<br />
So the address on the bus is <tt>%1……11111<span style="color: #0022ee;"><b>010</b></span>1</tt>, where the blue digits indicate the acknowledged interrupt level. So bits <b><tt>A0</tt></b> to <b><tt>A2</tt></b> are <tt>%101</tt> which selects output number 5. This instructs all attached cards to put their interrupt state on their assigned data line: '1' if inactive and '0' if active. Additionally, the data bus has pull-up resistors (initially for helping the 68008 with pulling them up for the K1-bus) which will make all unconnected data bits read '1' as well. <br />
<br />
So the vector read by the CPU is <tt>0xff – <b>x</b></tt>, where <b>x</b> is the active or potentially a combination of multiple active interrupts. If we never choose <b><tt>D7</tt></b> for the assigned data line of a card, the vector will always be in range <tt>0x80</tt> to <tt>0xFF</tt>, never conflicting with any other predefined vector. The vector table has to be filled with matching interrupt vectors. Wherever more than one bit is low in the vector address the program can decide which vector to store, e.g. always the vector of the interrupt with higher data bit number, thus implementing interrupt priorities.<br />
<br />
The CPU's <b><tt>A0</tt></b> is used for the strobe decoder's <b><tt>A0</tt></b> to enable word write instructions. The 68008 first writes the high byte to the even address and then the low byte to the odd address. If writing to the right address, this automatically first stores the high byte in the low-to-high data bus latch and then writes both bytes in a 16-bit K1-bus <b><tt>/WR_DATA</tt></b> cycle. Unluckily the same magic does not work for read cycles: the word will be read byte-swapped and must be swapped programmatically, which is a little bit awkward, because the 68000 CPU has no opcode for this.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAoBjHecikGGHOegZWKtPEJRDIejVtu6YubrlK0jY8HnvZgPQ-XHPteGaQsTEJwjnxX50WCWht_iS68SsGq788R0tA-MrG1KzrIqh5Ye7kcFMLxMS_BiHG4rwtorp_iVDmx6hht9Rb6Vw/s1600/hi_to_low.png" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAoBjHecikGGHOegZWKtPEJRDIejVtu6YubrlK0jY8HnvZgPQ-XHPteGaQsTEJwjnxX50WCWht_iS68SsGq788R0tA-MrG1KzrIqh5Ye7kcFMLxMS_BiHG4rwtorp_iVDmx6hht9Rb6Vw/s1600/hi_to_low.png" /></a><br />
<i>The low-to-high and the high-to-low data registers</i><br />
<br />
Data is stored in the low-to-high data register when the <b><tt>/WR_HI</tt></b> strobe signal is active, which means, that the CPU writes to an appropriate i/o address, and it put's it's contents on the high byte of the data bus when <b><tt>/WR_DATA</tt></b> is active, while the CPU supplies the low byte.<br />
<br />
There is a jumper option on the board to use <b><tt>/WR</tt></b> instead of <b><tt>/WR_DATA</tt></b> to enable the low-to-high latches outputs. This is to solve potential timing problems.<br />
<br />
The high-to-low data register reads data from the high byte of the data bus when <b><tt>/RD_DATA</tt></b> is active while the CPU reads the low byte, and it put's it's contents on the low data bus when <b><tt>/RD_HI</tt></b> is active, which means, that the CPU is reading from an appropriate i/o address.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgIOM9TGJItT91kFsAqJr7FDfLDbaN54Wshzex5t_eC_lMYtyr8kvndfFa71G6MnfkM4QcEjM263TUsQoxXI3CS2TxxU2Wu8k2YNqShQFz9_YiojRuhmaayEsyPCP_C_JiMt1ZpZfg9F0/s1600/i2c.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgIOM9TGJItT91kFsAqJr7FDfLDbaN54Wshzex5t_eC_lMYtyr8kvndfFa71G6MnfkM4QcEjM263TUsQoxXI3CS2TxxU2Wu8k2YNqShQFz9_YiojRuhmaayEsyPCP_C_JiMt1ZpZfg9F0/s1600/i2c.png" /></a></div>The I²C bus connection is centered around a <span style="color: #00bb00;">74HC367 2+4 bit driver</span> IC. The circuit is described on my <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/#example_cpu">K1-bus page</a>. <b><tt>A6</tt></b> and <b><tt>A7</tt></b> are chosen for data output to the I²C data and clock line. <b><tt>D7</tt></b> is used to read the state of the I²C data line. All I²C signals and timings are generated by the CPU under pure software control.<br />
<br />
The I²C bus is used to attach I²C EEPROMs which are used to automatically detect cards and which can provide <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/i2c-eeprom.pdf">driver code</a>.<br />
<br />
In addition, 2 LEDs are connected to the I²C driver for debugging the board. I spent some time to find a place to connect some lights, as this CPU board does not contain any i/o port pins.<br />
<br />
<b><tt>A8</tt></b> to <b><tt>A13</tt></b> of the CPU are connected to <b><tt>A0</tt></b> to <b><tt>A5</tt></b> ot the K1-bus. Also, there are pull-up resistors on <b><tt>A7</tt></b> to <b><tt>A13</tt></b>. This is because the 68008 CPU uses TTL levels for all signals and has only very poor high-driving capability, while the K1-bus is defined for symmetrical signals, as used by 74HCxx or 74ACxx series ICs.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_2QddKZrLS3UULQYxuiSeMt4_i5stZJ8U-_yHUD38F1GExB9aDed6_0HxhJ79CyTH-TqnYxYaZ94QiEK5_lNLvHNNRROYQqFSSINCWinxBPu89vdMaKA2Sjcx_wxlBRMqRFawW8kpmNo/s1600/reset+circuit.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_2QddKZrLS3UULQYxuiSeMt4_i5stZJ8U-_yHUD38F1GExB9aDed6_0HxhJ79CyTH-TqnYxYaZ94QiEK5_lNLvHNNRROYQqFSSINCWinxBPu89vdMaKA2Sjcx_wxlBRMqRFawW8kpmNo/s1600/reset+circuit.png" /></a></div>The reset circuit was already discussed in great detail <a href="http://kios-hardware-projects.blogspot.de/2014/01/68008-sram-microcomputer-reset-circuit.html">in January</a>:<br />
<br />
After power-up the capacitor is empty and current flows through it and through the base of transistor T1 which opens and pulls the <b><tt>/RESET</tt></b> line low. While <b><tt>/RESET</tt></b> is low T2 is closed. When C1 fills up the current decreases and at some point T1 does no longer drain all current from the <b><tt>/RESET</tt></b> line: the voltage rises and T2 will open and drain the remaining base current of T1 which will rapidly close: <b><tt>/RESET</tt></b> goes high and the system starts.<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-56197393234779886572014-08-06T21:30:00.002+02:002014-08-06T21:41:04.923+02:00Z80 Microcomputer with SRAM and K1-BusMy 68008 system is waiting for production and this is, because it uses only 1/2 of an Euro board which i prefer to order, because this size is the cheapest. So finally i finished a Z80 board for the K1-bus as well.<br />
<br />
The system consists of a CMOS Z80 CPU running at 6 MHz, one 32kB SRAM and one 32kB EPROM or EEPROM. It has no I/O except a K1-bus connector. The K1-Bus allows attachment of 16 bit peripherals. K1-bus card selection is restricted to D0 .. D7.<br />
<br />
<h3>Memory Map</h3><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRqQOM90dEB3FZrUU9m-yVXL5pwseeZviybT9hXfO83LzaLIei96aTnPE6RxvZeJAVfnAFx-sZAoe-K3SM_35WvuLJPQYztmyi73y_3R0IJHmYOV8x0d2nY1eXkNDVENYzX48fEivlcl4/s1600/memory.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRqQOM90dEB3FZrUU9m-yVXL5pwseeZviybT9hXfO83LzaLIei96aTnPE6RxvZeJAVfnAFx-sZAoe-K3SM_35WvuLJPQYztmyi73y_3R0IJHmYOV8x0d2nY1eXkNDVENYzX48fEivlcl4/s1600/memory.png" height="249" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"></div><br />
The Z80 uses separate instructions for I/O and memory access. Therefore the I/O address space is not part of the memory address space.<br />
<br />
RAM is mapped to $0000 .. $7FFF and ROM is mapped to $8000 .. $FFFF. This allows modifying the RST vectors at run time.<br />
<br />
After reset the ROM is mapped to the whole address space because the CPU starts execution at address $0000 and needs to find code there.<br />
<br />
Pin header JP3 allows using an EPROM or an EEPROM. The EEPROM is writable by the Z80.<br />
<br />
<br />
<h3>RAM / ROM select circuit</h3><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHGqisAEPQu4ShiQSqrUBaW7gGxWuaAqmLp-B3NaTRwbP5acrGKEfkNm_qZkcRxolpxglEQuClwcjQgRpGWLWySLjVFbVy488O4m46ppXyEatFDz_v76WJPadHiVdfMZGBniYuDExZRr8/s1600/memselect.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHGqisAEPQu4ShiQSqrUBaW7gGxWuaAqmLp-B3NaTRwbP5acrGKEfkNm_qZkcRxolpxglEQuClwcjQgRpGWLWySLjVFbVy488O4m46ppXyEatFDz_v76WJPadHiVdfMZGBniYuDExZRr8/s1600/memselect.png" height="93" width="400" /></a></div><br />
The <tt><b>RD</b></tt> and <tt><b>WR</b></tt> outputs of the CPU are directly connected to the RAM and ROM's corresponding inputs. Activation of the memory chips is done using their <tt><b>CE</b></tt> input.<br />
<br />
RAM is enabled when <tt><b>IORQ</b></tt> is low and <tt><b>A15</b></tt> is low,<br />
ROM is enabled when <tt><b>IORQ</b></tt> is low and <tt><b>A15</b></tt> is high.<br />
<br />
There is a 'init state FF' which is set by <tt><b>RESET</b></tt> and cleared by any I/O operation. Thus the FF is set after reset, will be cleared by the first I/O instruction and remain cleared throughout the rest of it's life. While it is set it forces <tt><b>A15</b></tt> high in the RAM/ROM select circuit so that the CPU will always read from ROM.<br />
<br />
<h3>Reset circuit</h3><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguyJ6KXhACZa6QlCqaVly8KShrIrZXWqMUHXUhPT_WmP61K8KxwU7rgDKHeIIionCT8PjLew4LU13J94e91ZI3pmYd7tbXlfjhih-Y0USuqrWLc3lrjmuG2BYT8SzPWF51q_ZuxeI-Yq8/s1600/reset.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguyJ6KXhACZa6QlCqaVly8KShrIrZXWqMUHXUhPT_WmP61K8KxwU7rgDKHeIIionCT8PjLew4LU13J94e91ZI3pmYd7tbXlfjhih-Y0USuqrWLc3lrjmuG2BYT8SzPWF51q_ZuxeI-Yq8/s1600/reset.png" /></a></div>The reset circuit was elaborated in great detail in my <a href="http://kios-hardware-projects.blogspot.de/2014/01/68008-sram-microcomputer-reset-circuit.html">hardware blog</a>. It is a little bit load dependent but should work up to 5mA pull-up current, which is much more than is to be expected, unless you attach a LED here. ;-)<br />
<br />
With the selected value of the timing capacitor the reset pulse will be approx. 2 ms.<br />
<br />
<br />
<h3 style="clear: both;">I/O</h3><br />
The CPU board does not contain any peripherals, not even a timer interrupt. All Peripherals are expected to be connected at the K1-bus.<br />
<br />
The K1-bus provides an I²C bus to attach EEPROMs with driver code and is 16 bit wide. Therefore two data latches are required for buffering data from the Z80's 8 bit bus to the upper half of the K1-bus.<br />
I/O therefore is divided into <i>I²C bus access</i>, <i>high-to-low</i> and <i>low-to-high</i> data latch access and <i>actual bus access</i>.<br />
<br />
The K1-bus is specified for symmetrical signals (HC, AC not HCT or TTL) therefore some signals may not have required levels without help.<br />
<br />
K1-bus <tt><b>IRPT</b></tt> is directly connected to the <tt><b>IRPT</b></tt> input of the CPU. The interrupt source is determined in software.<br />
<br />
K1-bus <tt><b>WAIT</b></tt> is directly connected to the <tt><b>WAIT</b></tt> input of the CPU. Any peripheral board which can issue <tt><b>WAIT</b></tt> fast enough can be used with this CPU board. Since the Z80 is pretty slow this probably means all peripheral boards.<br />
<br />
The K1-bus address lines <tt><b>A0</b></tt> to <tt><b>A5</b></tt> are directly connected to the corresponding CPU address lines. They are pulled up with 3.3kΩ resistors to help the CPU to pull them up: The CPU has very little driving capabilities and driving high is even less than driving low:<br />
<pre> IOL = 2.0mA @0.4V
IOH = -1.6mA @2.4V (which is too low for HC inputs)
IOH = -250µA @4.2V</pre>Eventually 4k7Ω is a better choice. To be tested.<br />
<br />
The K1-bus data lines <tt><b>D0</b></tt> to <tt><b>D7</b></tt> are directly connected to the CPU as well, which is an allowed design for very small systems. Expect problems with the third card added! They are pulled up with 3.3kΩ resistors to help the CPU to pull them up for the same reason as above. The K1-bus data lines <tt><b>D8</b></tt> to <tt><b>D15</b></tt> don't need pull-ups because they are driven by the 74HCT574 which has symmetrical outputs (though TTL inputs) and slightly higher driving capabilities as well.<br />
<br />
<h3>K1-bus select and strobe generation</h3><br />
Any I/O instruction addresses the K1-bus. This is centered around a 74HCT138 3-to-8 decoder. It is enabled by <tt><b>IORQ</b></tt>=0 && <tt><b>M1</b></tt>=1. It then activates one of 8 strobe lines, depending on <tt><b>A6</b></tt>, <tt><b>A7</b></tt> and <tt><b>WR</b></tt>. Pin headers JP4 allow to use <tt><b>A6</b></tt>, <tt><b>A7</b></tt> and <tt><b>A8</b></tt> instead and <tt><b>IORQ</b></tt> has a "strong" pull-up resistor. The reason for these circuit options are explained below.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzHzlrXf050_lnlgqf4Fd9dPeGb_gTru6cO9JqMNOJQXGT9itAuWKQ1sykyXVl6jxxrGhcu5BIVtOoNiQqTpLisEHghyphenhypheniDmMFAxm_7q6gfNZLrDLNnXwUeAA8yU6qHf5tGn-Bup06epcY/s1600/k1_strobes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzHzlrXf050_lnlgqf4Fd9dPeGb_gTru6cO9JqMNOJQXGT9itAuWKQ1sykyXVl6jxxrGhcu5BIVtOoNiQqTpLisEHghyphenhypheniDmMFAxm_7q6gfNZLrDLNnXwUeAA8yU6qHf5tGn-Bup06epcY/s1600/k1_strobes.png" height="125" width="400" /></a></div><br />
<h4>The following strobe signals are generated by the 74HCT138:</h4><br />
<tt><b>WR_SEL</b></tt><br />
Signal on the K1-bus to select a card for subsequent I/O operations. I/O cycles on the K1-bus do not contain the address of the talked-to card, instead a card must be 'selected'.<br />
<br />
<tt><b>RD_IRPT</b></tt><br />
Signal on the K1-bus to read in the interrupt states of all cards to detect which one actually activates the <tt><b>IRPT</b></tt> line.<br />
<br />
<tt><b>WR_IRPT</b></tt><br />
Signal on the K1-bus to mask off interrupts on some or all card. Can be used to implement interrupts with priority levels.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-5dHNkvN-ANJXYbbgM6fI6IP_AOOdqhWOBCmK4GIuj-9GnUOPAcMevrgO5I8Rvyr-CZEeZmx93dOt-iOJc3nsdjl0_KEI0U3Lh7s2GOSOfgOFhdIwo-frLltvHKe5BxzXw_qgmFsIuXg/s1600/k1_data_bus.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-5dHNkvN-ANJXYbbgM6fI6IP_AOOdqhWOBCmK4GIuj-9GnUOPAcMevrgO5I8Rvyr-CZEeZmx93dOt-iOJc3nsdjl0_KEI0U3Lh7s2GOSOfgOFhdIwo-frLltvHKe5BxzXw_qgmFsIuXg/s1600/k1_data_bus.png" height="201" width="640" /></a></div><br />
<tt><b>RD_DATA</b></tt><br />
Read data from a K1-bus card. The lower data byte is read by the CPU directly while the upper data byte (if present) is latched into the high-to-low data latch.<br />
<br />
<tt><b>WR_DATA</b></tt><br />
Write data to a K1-bus card. The lower data byte is supplied by the CPU directly while the upper data byte (if required) is supplied by the low-to-high data latch.<br />
<br />
<tt><b>WR_HI</b></tt><br />
Write one byte of data into the low-to-high data latch for use in the next (probably immediately following) <tt><b>WR_DATA</b></tt> cycle.<br />
<br />
<tt><b>RD_HI</b></tt><br />
Read the upper data byte from the last <tt><b>RD_DATA</b></tt> cycle from the high-to-low data latch.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP8Tnyx2tdjK1aPIEW_5XGXvx8FrQKMuBegvGLQZhUwdx6-Y9-zN0mO4OnxGYG6rr9kxuVlszrpZLs3tE4bFq1FzuGQgaJAuJKTNm_cr5hYqRWaYuOUaKMyx2o69S2lcMgXErvLuQBiWA/s1600/i2c.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP8Tnyx2tdjK1aPIEW_5XGXvx8FrQKMuBegvGLQZhUwdx6-Y9-zN0mO4OnxGYG6rr9kxuVlszrpZLs3tE4bFq1FzuGQgaJAuJKTNm_cr5hYqRWaYuOUaKMyx2o69S2lcMgXErvLuQBiWA/s1600/i2c.png" height="239" width="320" /></a></div><tt><b>RD_I2C</b></tt><br />
Read or write to the I2C bus. Both is done by reading. The I2C data and I2C clock lines are set by <tt><b>A6</b></tt> and <tt><b>A7</b></tt>, the value from the I2C data line is read on <tt><b>D7</b></tt>. The circuit is taken directly from my <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/#example_cpu">K1-bus page</a> and was the only idea i had to use only one IC.<br />
<br />
The two LEDs are for debugging. It took me some time to find a place for some debugging lights on a CPU board without any i/o circuitry (except K1-bus) on it. :-)<br />
<br />
<h4 style="clear: both;">74HCT138 enable:</h4><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzHzlrXf050_lnlgqf4Fd9dPeGb_gTru6cO9JqMNOJQXGT9itAuWKQ1sykyXVl6jxxrGhcu5BIVtOoNiQqTpLisEHghyphenhypheniDmMFAxm_7q6gfNZLrDLNnXwUeAA8yU6qHf5tGn-Bup06epcY/s1600/k1_strobes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzHzlrXf050_lnlgqf4Fd9dPeGb_gTru6cO9JqMNOJQXGT9itAuWKQ1sykyXVl6jxxrGhcu5BIVtOoNiQqTpLisEHghyphenhypheniDmMFAxm_7q6gfNZLrDLNnXwUeAA8yU6qHf5tGn-Bup06epcY/s1600/k1_strobes.png" height="125" width="400" /></a></div><br />
A Z80 I/O bus cycle is strobed with <tt><b>IORQ</b></tt> by the CPU, so this is the first signal used to enable the signal decoder. But the CPU issues this signal for interrupt acknowledge cycles as well. This can be distinguished by the <tt><b>M1</b></tt> signal, which is activated for interrupts but not for I/O cycles, so <tt><b>M1</b></tt> must be high to detect an I/O cycle. <tt><b>M1</b></tt> starts 2.5 cycles (that is: long) before <tt><b>IORQ</b></tt> and remains approx. 10ns longer active (<tt><b>M1</b></tt>: 80ns max. and <tt><b>IORQ</b></tt> 70ns max. after T3↑. These are marked with reference number 20 and 52 in the timing chart below) so it should be possible to use <tt><b>M1</b></tt> directly to mask the <tt><b>IORQ</b></tt> signal.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7eBpl-qnzhoCKsqq2NarG-abN2g3SBJjA3YuD19-tTqM2T-e7_b1MAMZAuFv0oBcj4rZm1xU5XAnYx_HgUk8X9nTIRGvxcRnydeByjiLQDsRTwtumgM46cjOEtSi_5CGavwCpYrqppto/s1600/Z80+Int+Ack+cycle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7eBpl-qnzhoCKsqq2NarG-abN2g3SBJjA3YuD19-tTqM2T-e7_b1MAMZAuFv0oBcj4rZm1xU5XAnYx_HgUk8X9nTIRGvxcRnydeByjiLQDsRTwtumgM46cjOEtSi_5CGavwCpYrqppto/s1600/Z80+Int+Ack+cycle.png" height="392" width="640" /></a></div><br />
Next is a timing problem: <tt><b>WR</b></tt> (and <tt><b>RD</b></tt>) and <tt><b>IORQ</b></tt> go up simultaneously: 70ns max. after T3↓ as can be seen in the I/O timing chart below. This may result in spurious pulses at arbitrary outputs of the 74HCT138.<br />
<i>note: T3 in an I/O cycle is one cycle earlier than T3 in an int ack cycle: int ack inserts 2 automatic wait cycles before T3 and I/O only one.</i> <br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQxJyHcER4WEl-ICgqd_29Dug8elJ31B3XtQXLD7eNDAhyphenhyphenPies5ffVzhl8X1JIdPOlrnmDt20WrfwbF29NpMOfuHj3Hi6m-BEWV1KfxtYwBQt5A-9QTwVlCM9l1i4dePck9G_spB7DQLY/s1600/Z80+I:O+cycle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQxJyHcER4WEl-ICgqd_29Dug8elJ31B3XtQXLD7eNDAhyphenhyphenPies5ffVzhl8X1JIdPOlrnmDt20WrfwbF29NpMOfuHj3Hi6m-BEWV1KfxtYwBQt5A-9QTwVlCM9l1i4dePck9G_spB7DQLY/s1600/Z80+I:O+cycle.png" height="409" width="640" /></a></div><br />
There are some ideas to overcome this:<br />
<br />
<ul><li>Make the <tt><b>IORQ</b></tt> signal end earlier:<br />
Problem: edges can be delayed and not be brought forward. So some very clever circuitry would be needed to do this.</li>
<li>Make the <tt><b>WR</b></tt> signal longer:<br />
Adding a delay to the signal would do the job. But it would also delay the starting edge of the signal: One HCT gate adds approx. 10ns, so the front edge would at least move from 60ns to 70ns, which is now after the 65ns of the <tt><b>IORQ</b></tt> signal. Whatever we do with the <tt><b>WR</b></tt> signal, it will always at least add one gate latency to the front edge as well! So this is no easy solution either.</li>
<li>Delay both signals to have time for front and end shaping:<br />
Unfortunately we don't have any time available for delaying the end of the <tt><b>IORQ</b></tt> signal: in an output cycle data is only guaranteed to be stable for 30ns after <tt><b>IORQ</b></tt> goes up (time #35) which is just enough to propagate <tt><b>IORQ</b></tt> through the '138 to the strobe signal (HCT: typ. 19ns, 40ns max, HC: typ. 17ns, 30ns max)</li>
<li>Use an address line instead of <tt><b>WR</b></tt>:<br />
This is what i do in the Z80 reference design on my K1-bus webpage. This is safe in respect to no spikes on the strobe lines but has a small risk of bus collisions, e.g. if a program crashes. Since all lower 8 address lines are currently used up, we'd need <tt><b>A8</b></tt> as well, which will make block I/O opcodes impossible to use. But this restriction could be limited to K1-bus cards which actually use all 6 address lines if we reassign the address lines, so that the rarely used K1-bus <tt><b>A5</b></tt> will be driven by Z80 <tt><b>A8</b></tt>. I will use this design as a fallback for safety. This is what pin-header JP4 in the "IO strobe signal decoder" image above is for.</li>
<li>Use a "strong" pull-up:<br />
A method i have already used on my K1 CPU is "signal shaping" with "strong" pull-ups: If you add a low pull-up or pull-down resistor which draws "high" current, it will aid signal flipping into the pull-up's direction and delay signal flipping in the other. Applying a "strong" pull-up to the <tt><b>IORQ</b></tt> signal will slightly delay the starting edge of the pulse and slightly bring forward the ending edge. So what is "strong" here? The CMOS Z80 can only sink 2.0mA @ 0.4V, so a pull-up which supplies just this will be a reasonable choice: This is approx. 2.5kΩ. Disadvantage: The amount of time which can be shifted this way is tiny: some few ns only, but they may just be enough here.</li>
</ul><br />
Besides <tt><b>WR</b></tt> (or <tt><b>A8</b></tt>, if nothing else works) <tt><b>A6</b></tt> and <tt><b>A7</b></tt> are chosen for strobe selection, because they are in the low address half, making all I/O instructions usable and they are the only unused address lines because <tt><b>A0</b></tt> to <tt><b>A5</b></tt> are already used for addressing K1-bus card registers.<br />
<br />
<h4>The board</h4><br />
This is a view of the component placement on the board. The board will be produced within the next few weeks in one go with the 68008 board because they can be placed on one Euro board (160x100mm). More material can be found on the <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%20Z80%20CPU%20board%20with%20SRAM/">project's web page</a> on my web site.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_1ImWaV-LPyXtvASmm62Ujn2EYZ7wqqjNmdVBM-XPnL0dCMQ1RWsVdDv939q2ccX87RbYih7obI4SqkYuleSTs0Fed259EKmKpF-4kBpTiLltfj8FokmNH1Riscy62ap8EYoYzlkrPcw/s1600/V1.0+placement.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_1ImWaV-LPyXtvASmm62Ujn2EYZ7wqqjNmdVBM-XPnL0dCMQ1RWsVdDv939q2ccX87RbYih7obI4SqkYuleSTs0Fed259EKmKpF-4kBpTiLltfj8FokmNH1Riscy62ap8EYoYzlkrPcw/s1600/V1.0+placement.png" height="301" width="400" /></a></div>Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-72700117540105920502014-04-27T16:54:00.006+02:002014-04-27T16:54:48.906+02:00Adding value to my Mac...Hi all,<br />
<br />
i just wanted to write some words about my new system disk and since this is kind of hardware...<br />
ok, here it goes.<br />
<br />
I bought an OCZ Vector 150 480MB SSD for my Mac.<br />
<br />
SSD<br />
+ Speed<br />
– Price<br />
<br />
Pro model<br />
+ write endurance: 5 years warranty x 50GB/day vs. 3 years warranty x 20GB/day<br />
– Price<br />
<br />
<b>And now Apple enters the Scene...</b><br />
<br />
I have a "late 2009 iMac" which means:<br />
1. Apple does not like me to open it<br />
2. There's a proprietary thermal sensor built in the current drive<br />
which is not documented but required or the fans spin up to maximum<br />
3. Apple deliberately does not support TRIM for non-Apple SSDs<br />
<br />
<b>ad 0: Copy data to new drive: </b>I copied all data with Carbon Copy Cloner from <a href="http://www.bombich.com/" target="_blank">bombich.com</a> beforehand from the internal HDD to the SSD which i had attached to the USB interface of my external backup drive. This took exceptional long, probably because i have some GB of hard linked files on it.<br />
<br />
<b>ad 1: Open the iMac:</b> find a pair of suction cups and a dust-free working place.<br />
<br />
<b>ad 2: Thermal sensor problem: </b>I found sources which said it's a 2N3904 transistor which sounds reasonable but there were signs for doubt: Shorting these 2 pins should silence the fan as well though shorting would move the measured voltage in the wrong direction. On the other hand in the mid 2009 model it <b><u>is</u></b> a transistor. So it might be. I consulted some data sheets and prepared to attach a BC337 as an external sensor.<br />
<br />
When my iMac was open i measured the diode voltage at the two pins of the HDD and found in one direction slightly more than 1V and in the other direction 0.36V which says: no, it's not a transistor. Nevertheless i attached the prepared transistor in the most likely direction. I can only guess now that it's in fact a 1-wire sensor.<br />
<br />
After restarting my Mac the fans sped up. For that "worst case" i had already downloaded SSD Fan Control from <a href="http://exirion.net/ssdfanctrl/" target="_blank">exirion.net</a>. I installed it.<br />
<br />
Unluckily the OCZ Vector does not have an internal temperature sensor, so the "intelligent" mode of SSD fan control does not work. I had to set a fixed value.<br />
<br />
<b>ad 3: TRIM support: </b>As in it's worst days when they were nearly broke Apple tests whether the found drive is one Apple provides itself and disables TRIM support for others. TRIM support informs the SSD which blocks are deleted in the file system and from now on do not need to be updated whenever neighbor blocks are written thus speeding up writing and reducing write wear on the SSD. So i ran the already downloaded TrimEnabler from <a href="http://www.cindori.org/software/trimenabler/" target="_blank">cindori.org</a>. This patches a kernel extensions, which means: it overwrites the test for the found model.<br />
<br />
<b>Unexpected Problem</b><br />
<br />
When i wanted to fit the SSD in it's 3"5 adapter into the iMac i found that OCZ uses metric screws whereas Apple is still stuck to 'imperial' units.<br />
<br />
<b>Cast in Order of Appearance:</b><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZBoWmnfG1qRyPuCUrfApSjibKPgSUbaq0UQNKy-NMC_mPJ2yTzKJkMGm134MATK3UUeRvaO3B1VBRkrexvEOVtH0a10M05YVoWP9bZigIbVBFoOGjmTmMDP04Qn-nqJy__OmFywAgfF8/s1600/Bildschirmfoto+2014-04-26+um+14.26.26.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZBoWmnfG1qRyPuCUrfApSjibKPgSUbaq0UQNKy-NMC_mPJ2yTzKJkMGm134MATK3UUeRvaO3B1VBRkrexvEOVtH0a10M05YVoWP9bZigIbVBFoOGjmTmMDP04Qn-nqJy__OmFywAgfF8/s1600/Bildschirmfoto+2014-04-26+um+14.26.26.png" height="117" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The Backup took exceptionally long: 3:30 hours for 232GB.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5tUpS4gl6JRAtVptDImW_oYLA_JcvMaGVu7sXRP9FIFcxwU9_8RCiupX1A08gx1ri7TrF_u2m4mLgGXMesIFR3AJL6nlXy4q0tk4kO-gLFxzvlxzSOyksGNyLDp9JsnXHZ0aKz0TqYHI/s1600/PICT1183.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5tUpS4gl6JRAtVptDImW_oYLA_JcvMaGVu7sXRP9FIFcxwU9_8RCiupX1A08gx1ri7TrF_u2m4mLgGXMesIFR3AJL6nlXy4q0tk4kO-gLFxzvlxzSOyksGNyLDp9JsnXHZ0aKz0TqYHI/s1600/PICT1183.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The SSD with the included 3"5 adapter</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6SuQWqDM0ulWRLWWzGKE90SOUYxXEKdWML246PKB4sJ2570_-dO-yyqIUnOlOslNAzLj9sGY0hjIguvf9Hvav3xwlVltAmJsytxPwCegFMO1nMpQBf3XA89tKcjfN2e0PnXPaMajwZek/s1600/PICT1192.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6SuQWqDM0ulWRLWWzGKE90SOUYxXEKdWML246PKB4sJ2570_-dO-yyqIUnOlOslNAzLj9sGY0hjIguvf9Hvav3xwlVltAmJsytxPwCegFMO1nMpQBf3XA89tKcjfN2e0PnXPaMajwZek/s1600/PICT1192.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The SSD attached to the USB interface of my external backup HDD.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7oT0VXV_CFIluTRqHrWz6a7VF8yI2eR0y40Z_x65q6RGysQ72a-Xf1Hecz22EKDBAdaVU20xaMRCFCVJkBtNT8PPsL3lleBvFwyWsn1urlxwKHaMoyrSdRq_nUITzwHOn4cfJWpznckY/s1600/PICT1200.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7oT0VXV_CFIluTRqHrWz6a7VF8yI2eR0y40Z_x65q6RGysQ72a-Xf1Hecz22EKDBAdaVU20xaMRCFCVJkBtNT8PPsL3lleBvFwyWsn1urlxwKHaMoyrSdRq_nUITzwHOn4cfJWpznckY/s1600/PICT1200.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The sensor which did not work. Also additional wire would not have been required.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmwb9iCyIP7p8P06rWaQvjCRXkl__iGiDyTKpxsGVthQKtdlyGOF9IV-dJLF3PUU5OA5JeEJJNjhRwRqdqqEMTfAQYgUEs7QBT5qPznIeOj3UkOxMbUFnjyZcqMnKXMOvjgscS9BN-L-I/s1600/PICT1213.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmwb9iCyIP7p8P06rWaQvjCRXkl__iGiDyTKpxsGVthQKtdlyGOF9IV-dJLF3PUU5OA5JeEJJNjhRwRqdqqEMTfAQYgUEs7QBT5qPznIeOj3UkOxMbUFnjyZcqMnKXMOvjgscS9BN-L-I/s1600/PICT1213.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">When lifting the front glass there was immediately lots of dust sucked in and settled on the display. <br />No chance to avoid this. (the screw is only to help auto focus)</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjziEvPvlavdviWqs5cexK9-xr88Z0AYp_xPkov8yxQkETjUjdZESOIEtK2oxQThJlHxQtN-Sto92ZCxQOQ5jw4q_rigpPEdtAZT7sStJVQ0ZfQZKFhC6Biesk_saUCELbTgeiDXpY8K3k/s1600/PICT1218.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjziEvPvlavdviWqs5cexK9-xr88Z0AYp_xPkov8yxQkETjUjdZESOIEtK2oxQThJlHxQtN-Sto92ZCxQOQ5jw4q_rigpPEdtAZT7sStJVQ0ZfQZKFhC6Biesk_saUCELbTgeiDXpY8K3k/s1600/PICT1218.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">My iMac with the old HDD, a Seagate Barracuda.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgselqRVFKhvHD0GJ_MIMdpWykypft7AtFgN2jr0S87bwFP8ftXxde2TibtfUxwjPf1scm54f0bDLdgiV2P_4VIQ1knPd1b_RDWEzhfJXe1v2eCNs0GxBzkdLIcRDWzC2YcU1df22e3QxA/s1600/PICT1233.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgselqRVFKhvHD0GJ_MIMdpWykypft7AtFgN2jr0S87bwFP8ftXxde2TibtfUxwjPf1scm54f0bDLdgiV2P_4VIQ1knPd1b_RDWEzhfJXe1v2eCNs0GxBzkdLIcRDWzC2YcU1df22e3QxA/s1600/PICT1233.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The SSD with the (not-working) sensor on it's 3"5 adapter fitted to the iMac's mounting bracket.<br />I had to find a way around that metric/imperial problem and placed the mounting bracket between adapter and SSD and pinched it with two screws.</td></tr>
</tbody></table>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh891BT0JbNglVwkB7eGENf87_VWCHxFqdK10xhw5hwuyOjiLFlHPByHbsvRrd09yBKb7pLUe6pffJL7i0Hyn2KoLL2ZjGAgW1Gzpy5rYbqxUCluoU-GOe9nYPgJJy8pcV7fEpd6wQvSsQ/s1600/PICT1242.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh891BT0JbNglVwkB7eGENf87_VWCHxFqdK10xhw5hwuyOjiLFlHPByHbsvRrd09yBKb7pLUe6pffJL7i0Hyn2KoLL2ZjGAgW1Gzpy5rYbqxUCluoU-GOe9nYPgJJy8pcV7fEpd6wQvSsQ/s1600/PICT1242.JPG" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The SSD placed in my iMac.</td></tr>
</tbody></table>
<b>Conclusion</b><br />
<br />
Especially program start now noticeably faster. I think it was worth it.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-40134105751126711812014-01-31T21:46:00.001+01:002014-04-11T23:01:42.208+02:0068008 SRAM Microcomputer - Software ToolchainHello,<br />
<br />
this is not nice. It's a PITA but everyone uses it: The Gnu Compiler Collection; here with a backend to produce m68k object code. I suffered for some hours, but then i had success: The first test program compiled! Let's see how it works. (and leave out most of whatever did not work.)<br />
<br />
Compiling the GCC is not a trivial task, you need a GCC and lot's of other tools, they should match each other, find each other and work on my desktop machine.<br />
<br />
Mac Ports (the port system i use on my Mac to port 'alien' stuff) was no help though right now i can see they provide a (very outdated) version of the <a href="http://www.rtems.org/wiki/index.php/Main_Page" target="_blank">rtems</a> tool chain. <i><span style="color: #93c47d;">Yesterday i installed a toolchain for ARM and the Mac Ports ARM GCC for Linux is so old that it even fails to install (it's from 2005, today is 2014!)</span></i><br />
<br />
<a href="http://wiki.osdev.org/GCC_Cross-Compiler" target="_blank">OSdev.org</a> is a great site but still a little bit over-complicated. <i><span style="color: #3d85c6;">(Ok, actually it's the GCC which is over-complicated.)</span></i><br />
<br />
Next was <a href="http://www.rtems.org/wiki/index.php/Main_Page" target="_blank">rtems.org</a>, a project for real-time embedded micro systems. The project supports the 68k CPUs but it's not the bare GCC but with their added extra. Maybe i'll cherry-pick some sources from them... :-) In the first place i didn't realize that this project already comes with a whole OS, else i had eventually skipped it. But so i downloaded the whole stuff from <span style="color: #0b5394;">rtems</span>.<br />
<br />
Starting from their <a href="http://www.rtems.org/wiki/index.php/Main_Page" rel="nofollow" target="_blank">start page</a> it was only <a href="http://www.rtems.org/wiki/index.php/Quick_Start" rel="nofollow" target="_blank">three</a> <a href="http://www.rtems.org/wiki/index.php/RTEMS_Source_Builder" rel="nofollow" target="_blank">clicks</a> away from <a href="http://www.rtems.org/ftp/pub/rtems/people/chrisj/source-builder/source-builder.html" target="_blank">rtems.org/ftp/pub/rtems/people/chrisj/source-builder/source-builder.html</a>.<br />
<br />
Following the instructions i did:<br />
<br />
<pre style="color: navy; font-family: 'Courier New', Courier, monospace; padding: 0px;"><span style="background-color: #fff2cc;">$ cd
$ mkdir -p development/rtems/src
$ cd development/rtems/src
$ git clone git://git.rtems.org/rtems-source-builder.git
$ cd rtems-source-builder
$ source-builder/sb-check
$ cd rtems
$ ../source-builder/sb-set-builder --list-bsets
$ ../source-builder/sb-set-builder --log=l-m68k.txt \
--prefix=$HOME/development/rtems/4.11 4.11/rtems-m68k</span></pre><br />
<span style="color: #6aa84f;"><i>(Actually i installed into a different directory, but that doesn't make much difference.)</i></span> After waiting roughly one hour a couple of new GCC instances entered this world.<br />
<br />
The <span style="color: #0b5394;">rtems</span> people have configured their installation scripts so that the resulting tool names all start with "m68k-rtems4.11-" which is different to "m68k-elf-" which is normally used. Probably there is a good reason for that.<br />
<br />
Next i stumbled over the <a href="http://bitsnbikes.blogspot.de/2010/02/das-blinklicht-with-gcc-elf-m68k.html" target="_blank">bitsnbikes</a> blogger site. J. Silva started a 68008 project in 2010 and described the sources for his first "project". He had borrowed from others and i borrowed from him:<br />
<br />
For the first successful test i needed 4 files and two commands:<br />
(You can find all files in my <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%2068008%20CPU%20board%20with%20SRAM/Software%200.01%20-%20first%20test%20program/" target="_blank">first project folder at little-bat.de</a>)<br />
<br />
<span style="background-color: #fff2cc;"> • "<span style="font-family: Courier New, Courier, monospace;">main.c</span>" the main source file with function main()</span><br />
<span style="background-color: #fff2cc;"> • "<span style="font-family: Courier New, Courier, monospace;">crt0.S</span>" an assembler file with the bootstrapping code</span><br />
<span style="background-color: #fff2cc;"> • "<span style="font-family: Courier New, Courier, monospace;">ldscript.ld</span>" a configure script for the loader</span><br />
<span style="background-color: #fff2cc;"> • "<span style="font-family: Courier New, Courier, monospace;">Makefile</span>" ah well, a Makefile</span><br />
<br />
<pre style="color: navy; font-family: 'Courier New', Courier, monospace; padding: 0px;"><span style="background-color: #fff2cc;">$ export PATH=$HOME/development/rtems/4.11/bin:$PATH
$ make</span></pre><br />
This actually produced an S-Record file which i can download into an Eprom. <b><i><span style="color: #6aa84f;">Fine!</span></i></b><br />
<br />
<pre style="color: navy; font-family: 'Courier New', Courier, monospace; padding: 0px;"><span style="background-color: #b6d7a8;">S00B0000746573742E53313949
S1130000000800000008000841F900000400203C3A
S113001000000400B1C06704421860F841F9000808
S1130020004E43F900000400203C00000400B089A5
S1130030670412D860F842A742A742A74EB9000845
S1110040004C4FEF000C6000FFFE00004E75F8
S9030000FC</span></pre><div><br />
</div><div>I don't know whether this will work because i haven't even built the hardware. <span style="background-color: #ffe599;">;-)</span><br />
<br />
The software toolchain for the 68008 board is up and running! <span style="background-color: #b6d7a8;">:-)</span></div><br />
... Kio !<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-35272337736858781382014-01-27T19:28:00.000+01:002014-07-16T17:00:00.510+02:0068008 SRAM Microcomputer – K1-Bus Circuit v0.4The design phase is coming to an end now, if no problems show up during verification phase later, this will be the K1-Bus I/O circuit:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXwUnyE11uo9FkIT9FCr2Vog7E439de29OHgYC3J6RsO5PGhnG4xudCSnP-FK9hkgEafeVYdAm_J8fL9Qvfnz4xB2zLHjkgBFy29sn3L7EYLhNmcoMOM-4vBUCX8KtVygplK4NWKg0Yws/s1600/v0.4+circuit+io.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXwUnyE11uo9FkIT9FCr2Vog7E439de29OHgYC3J6RsO5PGhnG4xudCSnP-FK9hkgEafeVYdAm_J8fL9Qvfnz4xB2zLHjkgBFy29sn3L7EYLhNmcoMOM-4vBUCX8KtVygplK4NWKg0Yws/s1600/v0.4+circuit+io.png" height="548" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="background-color: white; font-size: small; line-height: 14.784000396728516px;">K1-Bus 68008 CPU board with SRAM – K1-Bus I/O Circuit</span></td></tr>
</tbody></table><br />
<h3>Short summary of the K1-Bus</h3><br />
The <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/" target="_blank">➧ K1-Bus</a> is a 16 bit peripherals bus designed for simplicity. The basic unique concept of this bus is that the peripheral board accessed is not encoded in the address of each I/O opcode but the board to talk to must be <i>selected</i>. During selection the boards are addressed with a low level on their assigned data line.<br />
<br />
Interrupts are signaled on the <i>!K1_IRPT</i> collector line and during interrupt processing the CPU queries the interrupt state of all devices. The CPU can enable and disable interrupts for each device individually by writing a mask work on the data bus. This way all devices may be assigned an individual interrupt priority if the programmer desires.<br />
<br />
<b>There are 5 control lines (strobe signals):</b><br />
<ul><li><i>!SELECT</i> – The CPU writes a mask word on the bus to select a peripheral board for subsequent data transfer.</li>
<li><i>!WR_IRPT</i> – The CPU writes a mask word on the bus to enable or disable interrupts on the attached boards.</li>
<li><i>!RD_IRPT</i> – The CPU reads a mask word with the interrupt state of all attached boards.</li>
<li><i>!WR_DATA</i> – Send data to the selected device.</li>
<li><i>!RD_DATA</i> – Read data from the selected device.</li>
</ul><br />
<h3>The circuits</h3><br />
<b>The <u><span style="color: blue;">74HCT138</span></u> 3-to-8 line decoder </b>generates the <b>strobe signals</b> for the bus when <i>A19</i> is '<b>1</b>' during a bus cycle when <i>!AS</i> is low. <i>A0</i>, <i>A5</i> and the <i>!WR</i> signal are used to determine which signal to activate. For the reason to chose <i>A0</i> see below.<br />
<br />
<b>IC <u><span style="color: blue;">74HC367</span></u> with the surrounding resistors and diode</b> implement an <b>i2c interface</b>. Every K1-Bus extension board can provide an i2c EEprom with software driver for the board. Also, the i2c EEprom is used to detect the presence of the board. The funny circuit design is directly taken from my <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/#example_cpu" target="_blank">➧ K1-Bus</a> homepage. It was the simplest circuit i could come up with if no port pins are available to be used for the i2c bus.<br />
<br />
The i2c bus is always accessed by reading from the K1-Bus and one of the select lines of the <u><span style="color: blue;">74HCT138</span></u> 3-to-8 line decoder is used to address the <u><span style="color: blue;">74HC367</span></u>. <i>A6</i> and <i>A7</i> are forwarded to the <i>i2c data</i> and <i>clock</i> line while the <i>i2c data</i> line is also read and returned in <i>D7</i>. When the i2c bus is selected, the upper 4 drivers of the <u><span style="color: blue;">74HC367</span></u> are enabled. Then <i>A6</i> and <i>A7</i> are forwarded into the lower two drivers. When the upper drivers are disabled the resistors <i>R1</i> and <i>R2</i> feed back the output of the lower drivers to their inputs thus making them state keepers. So the low or high state of the i2c <i>data</i> and <i>clock</i> outputs are preserved until the next access is made to the <u><span style="color: blue;">74HC367</span></u>. The timing and protocol of the i2c bus must implemented in software. The i2c bus is <b>optional</b> but recommended unless you want to build a one-task computer which does not support to be extended later.<br />
<br />
The two LEDs <i>D4</i> and <i>D5</i> may be attached here during debugging. As the <u><span style="color: blue;">68008</span></u> CPU board does not have any I/O pins whatsoever, i have spent some time searching for a place to attach some status lights for initial testing. The LEDs should be removed when an I/O board is attached, because the LEDs may disturb operation of the i2c bus.<br />
<br />
<b>The two <u><span style="color: blue;">74HCT574</span></u> data latches</b> expand the 8-bit 68008 data bus to 16 bit for the K1-Bus. This is <b>optional</b> and only required if 16 bit extensions are actually attached. A serial card will probably be only 8 bit wide, but an IDE interface will most likely use the full bus width.<br />
<br />
When 16 bit data is written to the bus this is done in two stages: First the upper byte is written into the <u><span style="color: blue;">74HCT574 </span></u> low-to-high data latch. One output of the <u><span style="color: blue;">74HCT138</span></u> 3-to-8 line decoder provides the <i>!WR_HI</i> strobe. Next the low byte is written to the <i>!WR_DATA</i> address as usual. While the CPU provides the low byte the latch outputs are enabled simultaneously and put their data on the upper half of the bus.<br />
<br />
Note that only <i>A0</i> discriminates between <i>!WR_HI</i> and <i>!WR_DATA</i>. This way the program can perform a 16 bit write opcode to the even base address: The high byte will be written first to the even address (<i>A0</i>=0) and the low byte thereafter to the odd address (<i>A0</i>=1). That's really sweet! <b style="background-color: #ffe599;">:-)</b><br />
<br />
When 16 bit data is read from the bus this is also done in two stages: First the low byte is read using <i>!RD_DATA</i> as usual. This will also load the high byte from the K1-Bus into the high-to-low data latch. Then the high byte can be read from the latch. For this the <u><span style="color: blue;">74HCT138</span></u> 3-to-8 line decoder provides the <i>!RD_HI</i> strobe.<br />
<br />
Reading a 16 bit word is not as convenient as writing. Again <i>!RD_DATA</i> and <i>!RD_HI</i> are chosen to differ only in <i>A0</i> and the word can be read with one 16 bit read opcode, but the result will be byte-swapped. This cannot be avoided except with some more latches and drivers. So the program has to swap them thereafter and as the 68000 does not provide a byte-swap opcode (though it provides one for word swapping) the best is probably to do an 8-fold rotate left or right on the word data which is a 24 clock cycles time consuming operation.<br />
<br />
There are some <b>pull-up resistors and networks</b> related to the K1-Bus:<br />
<br />
The <i>!K1_IRPT</i> collector line has a pull-up because it must be driven with open drain outputs.<br />
<i>!K1_RESET </i>line has a pull-up for the same reason.<br />
<i>!K1_WAIT</i> has a pull-up in case no peripheral board is selected. <span style="color: #999999;">Whenever a board which uses the wait line is selected it must drive the wait line with a tri-state driver which actively pulls high and low. When a board is not selected it must not drive the wait line.</span><br />
<br />
<i>D0..D7</i> are pulled high with 3.3kΩ resistors. The data bus of the CPU is connected without bus drivers to the K1-Bus. This is possible for very small projects because the K1-Bus is defined to attach CMOS devices which draw only very little current, though switching the level on a line draws some current for the line capacitance which increases with line length and every device attached.<br />
<br />
The <u><span style="color: blue;">68008</span></u> CPU outputs TTL levels with very poor high-driving capability: 0.4mA only. The K1-Bus is defined for symmetrical signals as used by <i>74HC</i> or <i>74AC</i> types. This is in general no problem, only some timing parameters will shift a little. But as the <u><span style="color: blue;">68008</span></u> can only drive 0.4mA high (and still guaranteeing only 2.4V, so effectively driving even less than 0.4mA) these resistors are there to help the CPU with the '<b>1</b>' bits. 3.3kΩ result in 1.5mA when the outputs are low which is approx. 1/2 of what the CPU can drive low. Peripheral drivers also must provide this additional current for low bits, but 1.5mA should be ok with almost any IC.<br />
<br />
<i>A0..A5 </i>(on the K1 Bus) are pulled high for the same reason.<br />
<br />
<i>A6</i> and <i>A7</i> are pulled high for the same reason because they are attached to the <u><span style="color: blue;">74HC367</span></u> which is not a <u><span style="color: blue;">74HC</span><span style="color: red;">T</span><span style="color: blue;">367</span></u>. I'm too lazy to modify the circuit for a <u><span style="color: blue;">74HCT367</span></u> and i have <i>HCs</i> in stock, <i>HCTs</i> none.<br />
<br />
<b>More random notes:</b><br />
<br />
The <u><span style="color: blue;">74HCT574</span></u> high-to-low and low-to-high data latches were chosen to use <i>HCT</i> because when the CPU can operate the bus with TTL levels then the latches can do this as well. No need to read some data lines with <i>HC</i> circuits – keep it consistent.<br />
<br />
This CPU board can attach 16 bit K1-Bus extension boards. This means, it can read and write 16 bit data. But it cannot use the upper byte of the data bus for board selection: <i>!SELECT</i>, <i>!RD_IRPT</i> and <i>!WR_IRPT</i> all do not trigger a read or write of the high-to-low / low-to-high data latches. Therefore peripheral cards are limited to <i>D0..D7</i> for selection.Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-11213323938607908952014-01-26T13:43:00.000+01:002014-04-11T22:55:45.115+02:0068008 SRAM Microcomputer – Main Circuit v0.4The design phase is coming to an end now, if no problems show up during verification phase later, this will be the main circuit:<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBQyhm6k1e3uwuQrrJW7XQt5VHQRVzz2fCkHHSdO3X4ZPoSh6NnGzBViAhSwpEKgHPq3yAJgLMYWMYeYG3Vgjgks405SGMPQ6TsH9TzJgM_k1kGk09ixMEl_hXvJUESSirCygD-mB56D0/s1600/v0.4+circuit+main.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBQyhm6k1e3uwuQrrJW7XQt5VHQRVzz2fCkHHSdO3X4ZPoSh6NnGzBViAhSwpEKgHPq3yAJgLMYWMYeYG3Vgjgks405SGMPQ6TsH9TzJgM_k1kGk09ixMEl_hXvJUESSirCygD-mB56D0/s1600/v0.4+circuit+main.png" height="438" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">K1-Bus 68008 CPU board with SRAM – Main Circuit</td></tr>
</tbody></table><br />
Connection of the static Ram and Eprom are straight forward. Ram is mapped starting at address 0x00000 and the Eprom is mapped starting at 0x40000 by use of the 2-to-4 line decoder <i>IC2A</i>.<br />
<br />
After power-up the Eprom is forced into the address range of the Ram so that the reset vectors can be read from Rom. This is done by diode <i>D2</i> which pulls the input <i>A0</i> of <i>IC2A</i> high while the two-NAND-gate flip flop is in the power-up state.<br />
<br />
The address decoder <i>ICB2</i> either activates <i>!DTACK</i> or <i>!VPA</i> to terminate a bus cycle. <i>!VPA</i> is activated for addresses with <i>A19</i>=1 and <i>A14</i>=1 which will perform a slow <b>6800</b>-style memory cycle, for all other addresses <i>!DTACK</i> is activated. K1-Bus peripherals may add wait states by pulling <i>!K1_WAIT</i> low. By choice of <i>A14</i> to discriminate between fast and slow I/O all peripherals can be accessed using short addressing with <i>A15</i> to <i>A31</i> all '<b>1</b>'.<br />
<br />
The reset circuit has been described in all details in blog post <a href="http://kios-hardware-projects.blogspot.de/2014/01/68008-sram-microcomputer-reset-circuit.html">68008 SRAM Microcomputer – Reset circuit</a>.<br />
<br />
Multiple bus masters and single-stepping using the <i>!HALT</i> input are not supported. Bus errors are not detected. All bus cycles will terminate, unless someone pulls <i>!K1_WAIT</i> low. The CPU board does not have it's own timer interrupt and no own I/O pins. This must be provided by at least one attached K1-Bus peripheral board.<br />
<br />
For PCB images and Eagle CAD schematics you can view the project page at <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%2068008%20CPU%20board%20with%20SRAM/" target="_blank">k1.spdns.de/Develop/…</a>.<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-56684753511878209232014-01-25T15:20:00.000+01:002014-01-25T21:54:33.063+01:0068008 SRAM Microcomputer – Windows-in-a-BoxNow to something completely different: <span style="color: #274e13; font-size: x-large;">Software</span>.<br />
<br />
As i expect my 68008 computer not to work with an empty Eprom, i will probably have to program it. For this i have bought some years ago a <i>Genius NSP universal programmer </i>from <i>Shenzhen Stagger Electric</i>. No need to remember this name, they are probably folded. For good reason.<br />
<br />
I had installed the software on some kind of old Pentium Desktop running Windows 98 which i kept for this purpose only. But it's sitting in the Loft and i'd need to find a free space to work with it. Frankly, i want to get rid of it.<br />
<br />
The idea is to install a Windows in Virtual Box on my Mac. I have already a Linux Mint running in Virtual Box (every now and then) and i know there are free pre-built images of this or that operating system available in the net. I thought, i'd pick an XP image, get an XP license key from an unused pre-scrapped computer from my employer, install the image, register Windows and try whether i can attach the programmer through an USB-to-Serial connection.<br />
<br />
Good news: Microsoft offers <a href="http://www.modern.ie/en-us/virtualization-tools#downloads" rel="nofollow" target="_blank">pre-built Windows images</a> on it's web site for testing the IE and maybe non-commercial use (some websites say). They are not registered but they are freshly installed and the registration period has not yet started. Also, i got a Windows XP Home Edition key from my employer.<br />
<br />
I downloaded one of the XP images available, figured out how to combine the split <i>.rar </i>archive which consisted of one <i>.rar</i> file and one .<i>sfx</i> file (<u>how-to</u>: make the .<i>sfx</i> file executable and execute it) and imported the resulting .<i>ova</i> Virtual Box Appliance into Virtual Box. Made a snapshot. Started it.<br />
<br />
<b>Step One</b>: It was unregistered as expected and i tried to register my key. This did not work. It seems that the XP instance is a Windows XP Professional and probably this is the reason why the key is rejected. Ok, no problem, i have 30 days ahead.<br />
<br />
<b>Second step</b> is to install an anti virus software. I downloaded it with OSX, dropped it in a shared folder and installed it in XP. Yeah!<br />
<br />
<b>Third step</b> is to install Firefox. :-)<br />
<br />
<b>Fourth step</b> is to install this piece of crap, erm, the software for the Genius NSP programmer. I was afraid it could be on floppy disk, but it was on CD, and, yes, important, on a full-sized CD. I have a slot-in CD drive in my Mac and this matters. Installation worked within few seconds. My Mac is <i><u>SO</u></i> fast! <span style="background-color: #ffe599;">:-)</span><br />
<br />
I attached the programmer with an USB-to-Serial adapter to my Mac and started the software. As expected the software did not find the programmer. Ok, let's figure out why.<br />
<br />
Windows does not see the adapter. I investigate settings for the virtual machine and found a place to enable this specific USB device which instantly bothered me with the next problem: USB 2.0 controller enabled – you need the VirtualBox Extension Pack. Googled for it, downloaded it from Oracle, it automatically installed into Virtual Box – fine!<br />
<br />
After starting XP again and waiting for some seconds, it found 'new hardware'. Do i have a driver disk? hmm, no. Shall i search online for a driver? – yes. Wait. wait. I didn't find a driver. Mist. (Did it ever find a driver this way?)<br />
<br />
I figured out what is inside the USB adapter – a Prolific Technology Inc. USB-Serial Controller C, product ID 0x2303. So i downloaded the PL2303_Prolific_DriverInstaller_v1_9_0 driver from the <a href="http://prolificusa.com/pl-2303hx-drivers/" rel="nofollow" target="_blank">Prolific website</a> from OSX, moved it into the shared folder and installed it in XP.<br />
<br />
Ok installed. What's next? The Stagger software still doesn't find it. Hmm, given my experience with Windows i restarted it. And yes, now there is a <i>Prolific USB-to-Serial Comm Port</i> in the Device Manager and – ta ta – the NSP software can talk to the programmer! That's not a matter of course, because even if the serial communication works the software may do some weird things with the serial port, like bit-banging, and that is likely to fail with an USB adapter.<br />
<br />
I tried reading an Eprom and it looked like this:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVEYK61uEL-tFxKybzJWl9NDC8WI6iYHDr9UukIr7cSi1KJp8CzpEZ9NbebN0lZZmamGoacRJgx55ydOAS-vBzb9536HrPp8Nby8mo7J-Y8f237P4hyH5A-RHG930b8MO7JbhyuMRt5xY/s1600/NSP.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVEYK61uEL-tFxKybzJWl9NDC8WI6iYHDr9UukIr7cSi1KJp8CzpEZ9NbebN0lZZmamGoacRJgx55ydOAS-vBzb9536HrPp8Nby8mo7J-Y8f237P4hyH5A-RHG930b8MO7JbhyuMRt5xY/s1600/NSP.png" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Crappy NSP software reading my Eprom</td></tr>
</tbody></table>
<br />
Only partly translated, very poorly translated, window decoration around a transparent window. Buggy chip data base. Outdated now. <span style="background-color: #ea9999;">>:-)</span> But it works. Somehow.<br />
<div>
<br /></div>
<div>
Ok, i can throw away the old Windows 98 computer. Fine. <span style="background-color: #ffe599;">:-)</span></div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-4811351891657112132014-01-23T18:06:00.000+01:002014-01-23T18:56:11.567+01:0068008 SRAM Microcomputer – Free RunHello,<br />
<br />
yesterday i searched for some of the parts and put the <i><b>68008</b></i> on the bread board. According to other projects it is possible to do a "free run" by pulling all data lines to low. Though some people say it's the opcode of <i>NOP</i> it actually is some kind of <i>ORI</i>.<br />
<br />
I wanted to check some prerequisites of the project:<br />
<ol>
<li>Does the CPU work?</li>
<li>Can <i>!DTACK</i> (data acknowledge) be held permanently low?</li>
<li>Can <i>!VPA</i> (valid peripheral address) be used for instruction fetch cycle? </li>
</ol>
ad 1: <b>Yes</b> the CPU works. It cycles through it's address space and toggles <i>A19</i> with 2 Hz.<br />
ad 2: <b>Yes</b>, as i could tell the CPU works. <span style="background-color: #ffe599;">:-)</span><br />
ad 3: For curiosity: <b>Yes</b>. I believe that bus cycles and internal logic are completely separated and<i> !VPA</i> can be used for any bus cycle.<br />
<br />
Next interesting question: Can i put videos in my blog? It seems i can, but for a final verification i probably have to publish this page.<br />
<br />
Update: They are just converted into poor animated GIFs. I'll have to find something better... ok, uploaded them to youtube and embedded. back to the roots...<br />
<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><iframe frameborder="0" height="315" src="//www.youtube.com/embed/ufUai9lD7fE" width="420"></iframe></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Free Run using !DTACK-terminated bus cycles</td></tr>
</tbody></table>
To the left is the <b><i>68008</i></b> on my bread board and wired up to us <i>!DTACK</i> to terminate bus cycles. <i>!DTACK</i> is permanently low (active) and the CPU runs as fast as it can: At 8 MHz it does 2 opcode fetches per µsec or 2,000,000 opcode fetches per second. As the whole address space of the <i><b>68008</b></i> is 1 MB only, it cycles through it's address space 2 times a second. The most significant address bit <i>A19</i> should blink with 2 Hz. <i>A19</i> is the leftmost LED in the video and i hope you can verify that it blinks with 2 Hz. Thanks.<br />
<br />
An important result is that the <i><b>68008</b></i> actually works without deactivating <b>!DTACK</b> after each bus cycle. Though in all timing diagrams bus cycles start with <i>!DTACK</i> high it is actually possible to keep it low the whole time.<br />
<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><iframe frameborder="0" height="315" src="//www.youtube.com/embed/d7V8dShnoXg" width="420"></iframe></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Free Run using !VPA-terminated bus cycles</td></tr>
</tbody></table>
In the second video i used <i>!VPA</i> to terminate the bus cycles instead. This mode is intended to access old (really old!) <b><i>6800</i></b> peripherals but it seems true that you can terminate any bus cycle with <i>!VPA</i>, even an opcode fetch cycle. It's just slower. I was curious how slow actually, if every bus cycle uses <i>!VPA</i>, because the 68008 data sheet say it can be from 11 to 18 clock cycles long.<br />
<br />
Actually the <i>M68000 8-/16-/32-Bit Microprocessors User’s Manual Ninth Edition</i> says 10 to 19 cycles, while the <i>M68000 Family Reference Manual – MC68008 Technical Summary</i> says 11 to 18 cycles.<br />
<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://www.youtube.com/watch?v=d7V8dShnoXg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKMJotDC9HqTlhq5KxiiQcGMLqHRSY6Ndn7kEeahzsR8waFu2D_chDRjqCSJXKBOjvJs-tdGKfVrq3fkOAQgI0mU8msJ75XkxQ_GtWYsYtvWR9sZ6YEIHj8Sihk48ldgYdL_RYgqEGtgw/s1600/68008+VPA+bus+cycle+-+best+case+-+buggy+chart.png" height="227" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Buggy timing diagram for the 'best case' <i>!VPA</i>-terminated bus cycle</td></tr>
</tbody></table>
The latter puzzled me, because of course i started with the <b><i>68008</i></b> documentation, because that's the CPU i'm using, and i was wondering how fast the <b><i>68008</i></b> could uninterruptedly access the bus using the <i>!VPA</i> mode as 11 cycles is slower than the period of the free running <i>E</i> signal to which <i>!VPA</i> bus cycles are synchronized. But 10 to 19 makes sense (while 11 to 18 makes not) and i found an unnamed cycle in the <i><b>68008</b></i> manual's 'best case' chart (between the last 'w' cycle and 'S5') and i believe that someone reviewed the charts, found that the 'worst case' chart was only 18 cycles instead of 19 cycles long, demanded a correction and the missing cycle was added ... to the wrong chart. That's how real world works.<br />
<br />
In the second video one bus cycle takes 10 clock cycles instead of 4 and therefore <i>A19</i> should blink with 2 Hz *4 / 10 = 0.8 Hz instead. I think this approximately true.<br />
<br />
In my project the <i>!VPA</i> bus cycle is used to access slow peripherals on the K1 bus. But it is also used during interrupt acknowledge, in order to use an auto vectored interrupt. Now the interesting question is: Does the CPU actually perform a <i>!VPA</i> controlled bus cycle here or a dummy cycle, as it ignores the byte read?<br />
<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://www.youtube.com/watch?v=ufUai9lD7fE" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5-IZvnI6yeE7qESn6bK3quc27NFlujyq9DqWk7UnWOqGHHJWf1MaZqP-DK_by5R7ZWRWAfHOLINsIJc_pRJbqgEGJFx1jbz8A7dOxnONkHLfB31_hagtmdSchiwsTbaGGB_JTpPrIDSM/s1600/68000+int+ack+with+VPA.png" height="320" width="298" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>!VPA </i>used in interrupt vector read cycle</td></tr>
</tbody></table>
My guess was, that it actually does a <i>!VPA</i> controlled slow bus cycle if you activate <i>!VPA</i>, making interrupts approximately 10 clock cycles slower. And finally i found this chart on the last (!) page of the <i>M68000 8-/16-/32-Bit Microprocessors User’s Manual Ninth Edition</i>. The last pages are appendix B which is about interfacing <b><i>6800</i></b> devices and which are pasted into the document as bitmaps only. :-)<br />
<br />
The bus interface performs a slow memory cycle in the (dummy) interrupt vector read cycle if <i>!VPA</i> is activated to request an auto vector interrupt.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com2tag:blogger.com,1999:blog-1984932124087943660.post-30236173881515796502014-01-19T13:05:00.000+01:002014-01-19T13:50:30.255+01:0068008 SRAM Microcomputer – Unused 2-to-4 Line Decoder Got a Job!browsing through some other 68008 projects in the web<br />
<ul>
<li><a href="http://daveho.github.io/2012/10/13/an-mc68008-computer-project/" target="_blank">daveho.github.io</a> (unfinished)</li>
<li><a href="http://wandel.ca/homepage/mc68008/" target="_blank">wandel.ca</a> (documentation of older project)</li>
<li><a href="http://www.ist-schlau.de/" target="_blank">kiwi</a> that's a really adorable project!</li>
</ul>
i was reminded to the fact, that the 68000 has something called short addressing: Instead of supplying a 4-byte long address you only supply a 2-byte short address which is sign-extended to 4 bytes. This saves space in program code and – more important – up to 8 CPU clock cycles. So i took a look at my current address layout:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi51iCYZah8fdfc4-x9ATkwI13iFexY1SoZaF2BA4Ac4o6auWKQQ7lwvkmqU1xt0Wx8voESBeUDeL69kMZJDYfDZ7i7QPeHn1AlaHKv9leLMIOgbZHgFIZZ_HMdArY3FeHrNOVGI5qXBug/s1600/address+decoder+v0.2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi51iCYZah8fdfc4-x9ATkwI13iFexY1SoZaF2BA4Ac4o6auWKQQ7lwvkmqU1xt0Wx8voESBeUDeL69kMZJDYfDZ7i7QPeHn1AlaHKv9leLMIOgbZHgFIZZ_HMdArY3FeHrNOVGI5qXBug/s1600/address+decoder+v0.2.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">v0.2 address decoder</td></tr>
</tbody></table>
<br />
This allows the first 32k of RAM to be accessed with short addressing as well as the slow I/O address range, but not the fast I/O range:<span id="goog_1683553954"></span><br />
<ul>
<li><tt>%xxxxxxxx,xxxx00xx,xxxxxxxx,xxxxxxxx</tt> selects RAM and<br />
<tt><b>%</b>00000000,00000000,0xxxxxxx,xxxxxxxx</tt> is a possible subset of this which fit's in a signed word.</li>
<li><tt>%xxxxxxxx,xxxx01xx,xxxxxxxx,xxxxxxxx</tt> selects ROM and can never be accessed with short addressing.</li>
<li><tt>%xxxxxxxx,xxxx11xx,xxxxxxxx,xxxxxxxx</tt> selects slow I/O and<br /><tt>%11111111,11111111,1xxxxxxx,xxxxxxxx</tt> is a possible subset of this which fit's in a signed word as a negative value.</li>
<li><tt>%xxxxxxxx,xxxx10xx,xxxxxxxx,xxxxxxxx</tt> selects fast I/O and can never be accessed with short addressing.</li>
</ul>
In order to make all I/O short addressable, all I/O must have <i>A31</i> .. <i>A15</i> high. <i>A18</i> cannot be used to select between slow and fast I/O. The first Address line which can be used for that is <i>A14</i>:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7i-5yQX1QtHdk2pl-g_wwwg7LmItKQGm2MHBT6gzlqKuVGs-P_WzLUhXVTsduUe6RDkPgxv2MHkvmhToPXqALyJG2Xjhwa5oB8bGx3hykjAuVw471CJx5Wcwj1LXobM1XFmUtEdfahFw/s1600/address+decoder+v0.3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7i-5yQX1QtHdk2pl-g_wwwg7LmItKQGm2MHBT6gzlqKuVGs-P_WzLUhXVTsduUe6RDkPgxv2MHkvmhToPXqALyJG2Xjhwa5oB8bGx3hykjAuVw471CJx5Wcwj1LXobM1XFmUtEdfahFw/s1600/address+decoder+v0.3.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">v0.3 address decoder</td></tr>
</tbody></table>
<br />
Now the memory map is as follows:<span id="goog_1683553954"></span><br />
<ul>
<li><tt>%xxxxxxxx,xxxx00xx,xxxxxxxx,xxxxxxxx</tt> selects RAM and<br /><tt><b>%</b>00000000,00000000,0xxxxxxx,xxxxxxxx</tt> is a short addressable subset.</li>
<li><tt>%xxxxxxxx,xxxx01xx,xxxxxxxx,xxxxxxxx</tt> selects ROM (no short addressable subset).</li>
<li><tt>%xxxxxxxx,xxxx1xxx,x<span style="color: red;">1</span>xxxxxx,xxxxxxxx</tt> selects slow I/O and<br /><tt>%11111111,11111111,1<span style="color: red;">1</span>xxxxxx,xxxxxxxx</tt> is a short addressable subset.</li>
<li><tt>%xxxxxxxx,xxxx1xxx,x<span style="color: red;">0</span>xxxxxx,xxxxxxxx</tt> selects fast I/O and<br /><tt>%11111111,11111111,1<span style="color: red;">0</span>xxxxxx,xxxxxxxx</tt> is a short addressable subset.</li>
</ul>
There is no need to apply the post-reset <i>INIT</i> line pull-up to <i>A14</i> for the I/O address decoder and there is no need to strobe the outputs with <i>!AS</i> because the I/O control lines are strobed by <i>!AS</i> directly at the <u><span style="color: blue;">74HC138</span></u> which generates them (see other sheet – next to come <b style="background-color: yellow;">:-)</b>). It's even better this way because now <i>!SLOW_IO</i> which is directly connected to the CPU's <i>!VPA</i> input to request slow I/O or an auto vector toggles before <i>!AS</i> is valid and not shortly thereafter.<br />
<div>
<br /></div>
<div>
<b>Funny Note</b></div>
<div>
<br /></div>
<div>
Actually this second <i>2-to-4 line decoder </i>could be replaced entirely by one <i>NAND</i> gate: <i>!FAST_IO</i> is not used anywhere (actually it is currently used to reset the <i>INIT</i> line, but this could have been <i>!SLOW_IO</i> as well) and <i>!SLOW_IO</i> becomes low when <i>A14</i> and <i>A19</i> are both high, so, yes, that's a <i>NAND</i> function. The <i>NAND</i> gate would even be faster (the <u><span style="color: blue;">74HCT139</span></u> is pretty slow) but – i don't have a spare <i>NAND</i> gate, but i had a spare <i>2-to-4 line decoder</i>. <b style="background-color: yellow;">:-)</b></div>
<div>
<br /></div>
<div>
<div>
<br /></div>
</div>
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-72910218958261788822014-01-18T15:25:00.001+01:002014-01-26T22:08:49.776+01:0068008 SRAM Microcomputer – Reset circuit (Updated)Now to something very simple which i always have problems with: The reset circuit. It's only made from few parts but it's <span style="color: red; font-size: x-large;"><b>ANALOGOUS</b></span>. (shiver!)<br />
<br />
<b>Let's start with the requirements: </b><br />
<br />
For unknown reasons the 68008 CPU needs an excessively long reset pulse after power-up: 0.1 seconds! Because there are other circuits which may pull <i>!RESET</i> low, most namely the CPU itself, <i>!RESET</i> must be driven with an open collector or open drain output.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkBJFBZefcN-OWF860GUdUQX5ft-aDGJ62683sSjIes3e3jb7xgsIKd8SyU-S1iBGSTxvjm-GLRjPuaa8IGBIMCCqR4DOqdV0juAHFXgPwD7BAdf-2xaXdoX0Wns2yr677jZ1Tim2d1K4/s1600/reset.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkBJFBZefcN-OWF860GUdUQX5ft-aDGJ62683sSjIes3e3jb7xgsIKd8SyU-S1iBGSTxvjm-GLRjPuaa8IGBIMCCqR4DOqdV0juAHFXgPwD7BAdf-2xaXdoX0Wns2yr677jZ1Tim2d1K4/s1600/reset.png" height="293" width="320" /></a></div>
To the right is an image of the current circuit:<br />
<br />
<b>Let's discuss it. </b><br />
<i>This is very important because it's analogous and most times my analogous stuff doesn't work.</i><b> <span style="background-color: red;">:-/</span></b><br />
<br />
Start with <i>R9</i> + <i>R4</i> and ignore the rest: These two resistors form a voltage divider for Vcc and the voltage in the middle is 2.5V. (5V/2)<br />
<br />
Now add the capacitor: Initially it is discharged and behaves like a piece of wire. But as time goes by and current flows through it (and through the voltage divider) it charges and voltage across it increases which subtracts from the voltage present at the voltage divider. So the middle voltage of the voltage divider starts at 2.5V and drops over time to zero.<br />
<br />
Next add transistor <i>T1</i>: The first effect is that the middle voltage is shorted by the base-emitter diode of <i>T1</i> to ground, so the middle voltage is initially 0.7V, which is the break-through voltage of the diode, stays at that voltage for a while until it drops below 0.7V and resumes dropping as with no transistor present.<br />
<br />
While there is current sinked through the base-emitter diode, the transistor switches on, sinking the <i>!RESET</i> line to ground. As soon as the base-emitter voltage drops below 0.7V the transistor will switch off and <i>!RESET</i> rises to Vcc. We only have to choose the capacitance and the resistors appropriately, so that this will happen after approximately 0.1 second.<br />
<br />
But that's only half of the story: The transistor is not switched on or off depending on the voltage at it's base pin, instead the amount of current it can sink is a function of the current through the base-emitter diode. While this diode keeps the voltage at the base pin at 0.7V, the current through the diode needed to do this decreases as the voltage at the voltage divider decreases. So at some point in time the transistor is no longer fully able to sink all current from the <i>!RESET</i> line but only a part of it and the voltage on the <i>!RESET</i> line will not switch instantaneous to Vcc but will rise slowly.<br />
<br />
This is totally unreliable. <i>!RESET</i> must go away very fast, ideally within one CPU clock cycle. This is where <i>T2</i> and it's two associated resistors enter the game: While <i>!RESET</i> is low <i>T2</i> is switched off and the circuit behaves as if <i>T2</i> wasn't there. But when <i>!RESET</i> slowly rises above 0.7V <i>T2</i> will start to sink current. This will subtract from the base current of <i>T1</i> which will in return sink less current from the <i>!RESET</i> line and the voltage on the <i>!RESET</i> line rises even more which will open <i>T2</i> more which will ... Yes, a positive feedback and <i>!RESET</i> will rise very fast once it has reached 0.7V.<br />
<b><br />
</b> <b>Now let's examine power-up and power-down behavior.</b><br />
<br />
At power-up <i>C1</i> is empty. But the state of the <i>!RESET</i> line is unknown. If it rises with Vcc then <i>T2</i> will be open right from the start and may finish the reset pulse before it has been activated at all. It's very likely that it will do this because of the pull-up resistor on the <i>!RESET</i> line. To prevent this the voltage at the base of <i>T1</i> must be asserted to be clearly above 0.7V when <i>C1</i> is empty: This is true with the given values for <i>R4</i>, <i>R9</i> and <i>R12</i> (all 50kΩ) because when <i>C1</i> is empty the voltage at the voltage divider will be 1/3 Vcc which is approximately 1.65V and which will be sinked through the base-emitter diode of <i>T1</i>, opening <i>T1</i> which will pull <i>!RESET</i> low. <b style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;"><span style="color: #38761d;">Check.✓</span></b><br />
<br />
After a while capacitor <i>C1</i> is loaded (nearly) to Vcc and the input of the voltage divider is Vcc minus Vcap which is (nearly) 0V. When power is switched off, Vcc drops to 0V but the capacitor is still loaded, so the voltage at the voltage divider drops to -Vcc. We'll have to check the circuit that this does no harm. <b style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;"><span style="color: #38761d;">Check.✓</span></b><br />
<br />
Now the capacitor must be discharged, so that it is discharged when power is switched on again. This happens through the voltage divider <i>R4</i>+<i>R9</i> in approximately the same time as was required to load the capacitor after power-on. <b style="background-color: white; color: #222222; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.479999542236328px;"><span style="color: #38761d;">Check.✓</span></b><br />
<b><br />
</b> <b>Last step: calculate the values.</b><br />
<i><br />
</i> <i>!RESET</i> is pulled up by a <b>5kΩ</b> resistor which sources <b>1mA</b> at Vcc=5V and there is some more circuitry attached, so let's say <i>T1</i> must sink <b>5mA</b>.<br />
<br />
<i>T1</i> may have a current amplification of <b>100</b> (this is a value which widely varies even for transistors of the same type) so the base-emitter current of <i>T1</i> must be <b>~ 0.05mA</b>.<br />
<br />
This current must be sinked through the base-emitter diode of <i>T1</i> even after <i>C1</i> has charged to – let's say – <b>1/2</b> and the remaining voltage at the voltage divider is <b>2.5V</b>. This leaves a voltage drop of <b>~2V</b> across <i>R9</i>. Using the formula <span style="font-family: Courier New, Courier, monospace;"><b><u>U=R*I</u></b></span> <=> <span style="font-family: Courier New, Courier, monospace;"><b><u>U/I=R</u></b></span> we calculate the value for <i>R9</i> = <b>2/0.05e-3</b> = <b>40kΩ</b>.<br />
<br />
Next the capacitor voltage must rise <b>2.5V</b> (see above) during <b>0.1s</b> while being loaded with <b>0.05mA</b>. The formula for the capacitance is: <span style="font-family: Courier New, Courier, monospace;"><b><u>C = I*t/U</u></b></span>. So <i>C1</i> = <b>0.05e-3*0.1/2.5</b> = <b>2µF</b>. Because the calculation is very rough (actually we ignore <i>R4</i> which sinks some current as well and we should integrate the current over time because it's not const) so we double the capacitance. Fine adjustments will be made when it is built on the bread board. :-)<br />
<br />
<i><b>Note</b>: You didn't remember the formula for the capacitance? Using ISO units (not inch, miles and gallons) you don't need to look up the formula, you can construct it by pure logics:</i><br />
<br />
The capacitance depends on<br />
<br />
<ul>
<li>Charging current: higher current => higher capacitance => <b>C ~ I</b></li>
<li>Charging time: Current supplied for longer time => higher capacitance => <b>C ~ t</b></li>
<li>Voltage increase during charging time: Higher voltage increase allowed => less capacitance required => <b>C ~ 1/U</b></li>
<li>Using ISO units there will be no constant factor in the formula. Yeah!</li>
<li>therefore: <span style="background-color: #ffd966; font-size: large;"><span style="font-family: Courier New, Courier, monospace;"><b>C = I * t / U</b></span></span>.</li>
</ul>
<b>Alternatives</b><br />
<b><br />
</b> We could use a timer IC for the reset circuit, most likely a 555. But this would have a larger footprint than the discrete solution. Else we could use a mono-flop from the 74 series. But basically this increases the footprint even more (14 pin DIP instead of 8 pin DIP).<br />
<br />
Or use a counter. But even if fed from the E output of the CPU (which is CLK/10) we'd need to count up to 100,000 for 0.1 seconds which is impractical.<br />
<br />
I have also seen using a PIC for reset (basically because the project used a PIC for various control purposes) but using a CPU to generate the reset pulse for a CPU is a little bit ... over designed.<br />
<br />
<br />
<span style="color: #990000; font-size: large;">Update: Reset Circuit Test on the Bread Board</span><br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkBJFBZefcN-OWF860GUdUQX5ft-aDGJ62683sSjIes3e3jb7xgsIKd8SyU-S1iBGSTxvjm-GLRjPuaa8IGBIMCCqR4DOqdV0juAHFXgPwD7BAdf-2xaXdoX0Wns2yr677jZ1Tim2d1K4/s1600/reset.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkBJFBZefcN-OWF860GUdUQX5ft-aDGJ62683sSjIes3e3jb7xgsIKd8SyU-S1iBGSTxvjm-GLRjPuaa8IGBIMCCqR4DOqdV0juAHFXgPwD7BAdf-2xaXdoX0Wns2yr677jZ1Tim2d1K4/s1600/reset.png" height="293" width="320" /></a></div>
Today i tested the circuit and as expected it did not work as expected. Let's see why. For your convenience to the right is another image of the circuit.<br />
<br />
As discussed above resistor R12 must be high enough so that T1 actually switches on at power-up.<br />
<br />
<b>Full flip requirement:</b><br />
<br />
But there's another requirement for R12: It must be able to sink the whole current which flew through the base-emitter diode of T1 when T2 switches on. Else there will be some base current left at T1 and it will not fully close and therefore the voltage at the reset line will not fully rise to +5V.<br />
<br />
To estimate this current is a little bit tricky: It depends on the pull-up current on the reset line and the transistor's current amplification. Worst case is high pull-up current and low current amplification:<br />
<br />
<span style="background-color: white;">• I<span style="font-size: xx-small;">CE</span> = 5 mA</span><br />
<span style="background-color: white;">• h<span style="font-size: xx-small;">FE</span> = 100</span><br />
<span style="background-color: cyan;"><br /></span>
<span style="background-color: white;">=> I<span style="font-size: xx-small;">BE</span> ≥ 5mA/100 = 50µA</span><br />
<div>
<br /></div>
<span style="background-color: #ffe599;">R12 ≤ U<span style="font-size: xx-small;">R12</span> / I<span style="font-size: xx-small;">R12</span> = (0.65V-0.2V) / 50µA = 9kΩ</span><br />
<br />
where 0.65V = break-through voltage U<span style="font-size: xx-small;">BE</span> of the transistor's base-emitter diode<br />
and 0.2V = saturation voltage U<span style="font-size: xx-small;">CE</span> between collector and emitter.<br />
<br />
So R12 must be <b>at most 9kΩ</b> to ensure a full flip when T2 opens.<br />
<br />
<b>Power-up requirement:</b><br />
<br />
Immediately after power-on we require that T1 opens, even if T2 is also open due to the pull-up resistor on the reset line. For practical reason we assume C1 not completely empty but discharged to 1V, which leaves 4V at R9. So the current across R9 is:<br />
<br />
<span style="background-color: #ffe599;">I<span style="font-size: xx-small;">R9</span> = (4V-0.65V) / 50kΩ = 67µA</span><br />
<br />
where 0.65V = break-through voltage U<span style="font-size: xx-small;">BE</span> of the transistor's base-emitter diode<br />
<br />
This current now flows through R4, R12 and T1:<br />
<br />
I<span style="font-size: xx-small;">R4</span> = 0.65V / 50kΩ = 13µA<br />
I<span style="font-size: xx-small;">BE</span> ≥ 50µA<br />
I<span style="font-size: xx-small;">R12</span> ≤ (67µA-13µA-50µA) = 4µA<br />
R12 ≥ (0.65V-0.2V) / 4µA = 112.5kΩ<br />
<br />
where 0.65V = break-through voltage U<span style="font-size: xx-small;">BE</span> of the transistor's base-emitter diode<br />
and 0.2V = saturation voltage U<span style="font-size: xx-small;">CE</span> between collector and emitter.<br />
<div>
<br /></div>
So R12 must be <b>at least 112.5kΩ</b> to ensure that T1 is initially open at power-up even if T2 is open.<br />
<br />
<b><span style="color: #990000; font-size: large;">Gotcha! We're trapped!</span></b><br />
<br />
Can we solve this?<br />
<br />
First, we were calculating with worst-case values. We could require better worst cases. Second, we can adjust R4.<br />
<br />
<b>Power-up requirement with new R4 value:</b><br />
<div>
<br /></div>
<div>
R4 is used to make the circuit a bit independent of the current amplification of T1 and of the pull-up current on the reset line and it is needed to discharge C1 when power is off. We can't remove it entirely but we could double it's value which will half the current through it and redo the above calculations:</div>
<div>
<br /></div>
<div>
I<span style="font-size: xx-small;">R4</span> = 0.65 / <span style="background-color: lime;">100kΩ</span> = <span style="background-color: white;">6.5µA</span></div>
<span style="background-color: white;">I<span style="font-size: xx-small;">BE</span> ≥ 50µA</span><br />
<div>
<span style="background-color: white;">I<span style="font-size: xx-small;">R12</span> ≤ (67µA-6.5µA-50µA) = 10.5µA</span></div>
<div>
<span style="background-color: white;">R12 ≥ (0.65V-0.2V) / 10.5µA = 43kΩ</span><br />
<br />
Now R12 must be <b>at least 43kΩ</b> to ensure that T1 is initially open at power-up even if T2 is open. Much better. <b><span style="color: #38761d;">:-)</span></b></div>
<div>
<br /></div>
<b>Full flip requirement with reduced maximum pull-up current on the reset line:</b><br />
<div>
<b><br /></b></div>
The other two screws are the current amplification of T1 and the pull-up current on the reset line.<br />
<br />
The allowed pull-up current was defined as 5mA which means a pull-up resistor as low as 1kΩ. Let's reduce this to 2.5mA which is still much more than we expect, because the actually used value is 5kΩ, but there may be some current added from the attached devices, though this should be negligible. Let's redo the calculations:<br />
<br />
<span style="background-color: white;">I<span style="font-size: xx-small;">BE</span> ≥ </span><span style="background-color: lime;">2.5mA</span><span style="background-color: white;">/100 = 25µA</span><br />
<div>
<br /></div>
<span style="background-color: #ffe599;">R12 ≤ U<span style="font-size: xx-small;">R12</span> / I<span style="font-size: xx-small;">R12</span> = (0.65V-0.2V) / 25µA = 18kΩ</span><br />
<div>
<span style="background-color: #ffe599;"><br /></span></div>
So R12 must be <b>at most 18kΩ</b> to ensure a full flip when T2 opens.<br />
<div>
<br /></div>
<div>
<b>Power-up requirement with reduced </b><b>maximum </b><b>pull-up current on the reset line:</b></div>
<div>
<b><br /></b></div>
<div>
I<span style="font-size: xx-small;">R4</span> = 0.65 / <span style="background-color: lime;">100kΩ</span> = 6.5µA</div>
<div>
I<span style="font-size: xx-small;">R12</span> ≤ (67µA-6.5µA-<span style="background-color: lime;">25µA</span>) = 35.5µA</div>
<div>
R12 ≥ (0.65V-0.2V) / 35.5µA = 12.75kΩ<br />
<br />
So R12 must be <b>at least 12.75kΩ</b> to ensure that T1 is initially open at power-up even if T2 is open.</div>
<div>
<br /></div>
Both requirements are met if we <b>use 15kΩ</b> for R12. <span style="color: #38761d;"><b>Fine. :-)</b></span><br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuxSz8gk55ZKyDqH-GoK9RH2cF9ZEmmrZNvW7kp6XTuFtjvWg760MagHb-9n8DrOUpTCpSBCxEsA3qvAvF00x8HSgX1uH8K0w02ZlZJ8ktlnnwhyphenhyphenxNwG7E-E1W3-y4SIeNHkC6BBnygtQ/s1600/v0.4+reset.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuxSz8gk55ZKyDqH-GoK9RH2cF9ZEmmrZNvW7kp6XTuFtjvWg760MagHb-9n8DrOUpTCpSBCxEsA3qvAvF00x8HSgX1uH8K0w02ZlZJ8ktlnnwhyphenhyphenxNwG7E-E1W3-y4SIeNHkC6BBnygtQ/s1600/v0.4+reset.png" height="291" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Reset circuit with validated resistor values</td></tr>
</tbody></table>
To the left is the updated reset circuit as tested on the bread board. Actually i had still problems with the power-up reset if C1 was not completely empty, but that was due to a LED which i connected to the reset line to show it's state. It had clearly more than 5mA.<span style="color: #38761d;"> <b>:-)</b></span><br />
<br />
<br />
<br />
<div>
<br /></div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-55839058294528455272014-01-17T19:28:00.000+01:002014-01-26T13:44:34.806+01:0068008 SRAM Microcomputer – Main Circuit v0.2Wow, version 0.2 of the circuit released!<br />
<br />
i worked on the main circuit and removed 2 (two!) of the four glue logic ICs. Wow! This is <span style="color: #990000;"><b>near-Sinclair</b></span>. I could remove one more IC and become <span style="color: #990000;"><b>equal-Sinclair</b></span>. Or remove both remaining glue ICs and become <span style="color: #990000;"><b>super-Sinclair</b></span>.<br />
<br />
What does this <strike>nonsense</strike> mean?<br />
<br />
You know i come from the <a href="http://k1.dyndns.org/Vintage/Sinclair/" target="_blank">Sinclair ZX Spectrum</a> side of the universe (as opposed to the C64) and i have certain ideas about how Sir Sinclair worked. What he did was like this:<br />
<br />
<ul>
<li>Use the cheapest components,</li>
<li>reduce the design to the absolute minimum</li>
<li>and then take away one more part.</li>
</ul>
<div>
<br /></div>
That is <span style="color: #990000;"><b>equal-Sinclair</b></span>. It seems that <span style="color: #990000;"><b>Sinclair</b></span> is a measure for uselessness. Currently my design is only <span style="color: #990000;"><b>near-Sinclair</b></span>, because i still could take away some parts. Let's take a look at the current circuit (version 0.2) and discuss it:<br />
<br />
<i><b><span style="color: #0b5394;">Hint:</span></b> right-click on the image and open it in another window if you want to keep it visible while you read on!</i><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGmhMFa0QfCPUy4qYdjGJBIQZrMmLGWCeH5UMae_Oad5IAYRerxbE70kXMUxmh8Jr65fkxJpKknBYqYw316dsgrp0TFH8qswJlr5p7IP047Pfbt81JK2Vz0U0HaYllV8nFyaRNf11DN2A/s1600/Bildschirmfoto+2014-01-17+um+17.00.54.png" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGmhMFa0QfCPUy4qYdjGJBIQZrMmLGWCeH5UMae_Oad5IAYRerxbE70kXMUxmh8Jr65fkxJpKknBYqYw316dsgrp0TFH8qswJlr5p7IP047Pfbt81JK2Vz0U0HaYllV8nFyaRNf11DN2A/s1600/Bildschirmfoto+2014-01-17+um+17.00.54.png" height="414" width="640" /></a></div>
<i>Main circuit diagram with everything except the K1 bus and non-functional parts, e.g. capacitors.</i><br />
<br />
As you can see there are only two glue ICs: one Quad NAND <i><span style="color: blue;">74HCT00</span></i> and a Dual 2-to-4 line decoder <i><span style="color: blue;">74HCT139</span></i> with only one decoder actually used.<br />
<br />
<b>The 2nd NAND</b> <u><span style="color: blue;">IC7C</span></u> is used as an inverter and constructs a <i>!RD</i> signal from the CPU's <i>!WR</i> signal, required by the RAM and the ROM.<br />
<br />
<b>The next two NANDs</b> construct a flip flop, which is set by <i>!RESET</i> to indicate the initialization phase after system reset. The <i>INIT</i> signal from this flip flop is used to pull A18 high at the input of the 2-to-4 decoder <u><span style="color: blue;">IC2A</span></u>. (The resistor <span style="color: blue;"><u>R5</u></span> and the diode <u><span style="color: blue;">D2</span></u> actually construct an OR gate without wasting 3 unused gates in a 74HCT32.)<br />
<br />
This is used to circumvent a design flaw in the 68000 microprocessor series: After reset the supervisor stack pointer and the program counter are read from addresses 0x00000.l and 0x00004.l respectively so there must be ROM mapped in. But then the whole vector table of the cpu is located here; actually roughly the first 1 kByte of memory is used for vectors. It is very desirable to have these in RAM because otherwise you cannot change them without a secondary vector table in RAM which is jumped to by the vectors in ROM. So you need ROM after reset but you prefer RAM here at any other time. The normal memory layout is RAM at address 0x00000 as you can see from the 2-to-4 decoder outputs, but during initialization A18 is pulled high so that the processor, when trying to read from address 0x00000 and 0x00004 reads from the ROM instead. After that the first memory access to the slow I/O address range will also reset the NAND flip flop and A18 is no longer forced high and the RAM can be accessed.<br />
<br />
After we know where the <i>!SLOW_IO</i> signal comes from we can understand what <b>the first NAND</b> gate <u><span style="color: blue;">IC7D</span></u> does: If <i>!WAIT</i> is high and <i>!SLOW_IO</i> is high then the <i>!DTACK</i> signal to the CPU is low (asserted). The <i>!DTACK</i> signal is used to terminate a normal bus cycle of the CPU, either memory or other bus access. <i>!DTACK</i> will not be asserted when <i>!WAIT</i> from the K1 bus is active, thus implementing the wait processing for the K1 bus, or when <i>!SLOW_IO</i> is low which means a memory access to an address with A18=1 and A19=1. This memory range is used for slow I/O (sic!) and shall use the 6800 peripherals slow addressing mode, which is signaled to the CPU by pulling it's <i>!VPA</i> entry low instead of activating <i>!DTACK</i>. You can see that <i>!SLOW_IO</i> is directly connected to <i>!VPA</i> of the CPU. So either <i>!DTACK</i> is asserted (for the first 3 memory ranges, eventually suppressed by <i>!WAIT</i>) or <i>!VPA</i>.<br />
<br />
<b>Trick</b>: Connecting <i>!SLOW_IO</i> to <i>!VPA</i> has a second effect: This also requests the CPU to use an auto-vector from it's vector table for interrupts. When an interrupt is acknowledged and the CPU reads the vector number for this interrupt, most address lines are pulled high, most notably A18 and A19, which will activate <i>!SLOW_IO</i> which activates <i>!VPA</i> which requests an auto-vector if it is pulled low during an interrupt acknowledge cycle. We only have to take precautions that this not also performs spurious I/O on the K1 bus; but that's on the other sheet. :-)<br />
<br />
That's all about the glue logics. Not supported are:<br />
<br />
<ul>
<li>Bus arbitration for multiple bus masters</li>
<li>Bus error or any other exception signaling</li>
</ul>
<br />
<h3>
How to become <span style="color: #990000;">Equal-Sinclair</span></h3>
<br />
Let's remove the Quad NAND IC. Will it still work?<br />
<br />
If we remove <b>the first NAND</b> <i><span style="color: blue;">IC7D</span></i> then we'll lose wait handling for the K1 bus. Ok, well, that may be acceptable. But we'll still need an inverter here to invert <i>!SLOW_IO</i> to <i>!DTACK</i>.<br />
<br />
To solve this, we could connect A19 directly to <i>!DTACK</i>, so whenever the CPU accesses RAM or ROM <i>!DTACK</i> will be asserted. But then we'll lose <i>!FAST_IO</i> because whenever <i>!DTACK</i> is not asserted <i>!VPA</i> must be asserted instead to finish the bus cycle. So <i>!VPA</i> must be connected to <i>!A19</i>. How can we invert A19? We can use the unused gate from the Dual 2-to-4 decoder. If we have no fast I/O we also need no wait cycle handling. <b>:-)</b> <b><span style="color: #38761d;">Check.✓</span></b><br />
<br />
If we remove <b>the second NAND</b> <i><span style="color: blue;">IC7C</span></i> then we'll lose the <i>!RD</i> signal. This is acceptable: <i>!OE</i> of the ROM can be tied high so whenever the ROM is enabled it puts it's data on the bus. Disadvantage: If the CPU writes to the ROM then there'll be a collision on the data bus. We'll have to be cautious.<br />
<br />
<i>!OE</i> of the RAM can also tied high. When <i>!WR</i> is enabled this will supersede the <i>!OE</i> signal. (eventually this is not true for all RAMs, but RAMs exist which can be operated in this way). <b><span style="color: #38761d;">Check.✓</span></b><br />
<br />
If we remove <b>the NAND flip flop</b>, we'll no longer have the <i>INIT</i> signal. Ok, let's remove the resistor-diode OR gate as well and let's swap <i>!ROM_CE</i> and <i>!RAM_CE</i>. ROM has to be at address 0x00000 and we can't modify the vector table in ROM. <b><span style="color: #38761d;">Check.✓</span></b><br />
<br />
<b>Summary</b>: Yes, we can become <b><span style="color: #990000;">Equal-Sinclair</span></b>! We just have no fast I/O and we'll have to live with the vector table in ROM. <b><span style="color: #38761d;">That's easy.</span></b><b><span style="color: #38761d;">✓</span></b><b><span style="color: #38761d;">✓</span></b><b><span style="color: #38761d;">✓</span></b><br />
<br />
<h3>
How to become <span style="color: #990000;">Super-Sinclair</span></h3>
<div>
<br />
Obviously we must remove the Quad 2-to-4 line decoder as well. Will it still work? Ok, that's real hard, but <b><span style="color: #990000;">Super-Sinclair</span></b> IS real hard. You get a "Sir" for <span style="color: #990000;"><b>Equal-Sinclair</b></span>, right?</div>
<br />
First let's remove the gate used to construct <b>the inverter for address line A19</b> which we just have added to become <b><span style="color: #990000;">Equal-Sinclair</span></b>. Now we have the choice: We could build an inverter from two resistors and one transistor or we could ... leave it out. Yes, that's what Sir Sinclair had done. <b>:-)</b><br />
<br />
We either need <i>!VPA</i> to be asserted during interrupt acknowledge or we must to supply a vector address. Both is possible:<br />
<br />
<b>Supply <i>!VPA</i></b>: Tie <i>!VPA</i> fixed low and <i>!DTACK</i> fixed high and the CPU will do all bus cycles in 6800 mode. Will be a little slow though. We'll have slow memory access and only slow I/O.<br />
<br />
<b>Supply <i>!DTACK</i></b>: Tie <i>!VPA</i> fixed high and <i>!DTACK</i> fixed low and the CPU will do all bus cycles in standard mode. We'll have fast I/O (with no wait cycles) but no slow I/O. During an interrupt acknowledge cycle we'll have to provide a vector number on the data bus. We can use a resistor network to pull up all data lines if no one else drives the bus, then the vector number will be 0xFF (255). <b><span style="color: #38761d;">Check.✓</span></b><br />
<br />
Now – <i><b>shiver!</b></i> – let's remove the <b>address range decoder</b>. Can we provide <i>!RAM_CE</i>, <i>!ROM_CE</i> and <i>!FAST_IO</i> (no need for <i>!SLOW_IO</i>) somehow else?<br />
<br />
Yes, we can! We can use 3 address lines directly to do that:<br />
• Use A17 for <i>!RAM_CE</i>,<br />
• A18 for <i>!ROM_CE</i> and<br />
• A19 for <i>!FAST_IO</i>.<br />
<br />
Drawbacks:<br />
Each range is limited to 128 kByte. (A0..A16) <span style="color: #38761d;"><b>Accepted.</b></span><br />
There will be be bus collisions if the program accesses addresses with more than one of A17 .. A19 low. <b style="color: #38761d;">Accepted.</b><br />
There may be short bus collisions when the address lines toggle between bus cycles. <b style="color: #38761d;">Accepted.</b><br />
After reset the CPU will read from address 0x00000.l and 0x00004.l <b style="color: #990000;">Uh uh... </b>This will read from RAM, ROM and IO simultaneously. And any other vector will be read from this page with triple-collision as well. <b><span style="color: #990000;">That's bad.</span></b><br />
<br />
I'm a programmer and i'm here to find solutions: We have to disable RAM and IO when the ROM is selected. This will also reduce the forbidden address ranges with bus collisions.<br />
<br />
We can get the RAM out of the way by its positive <i>CE</i> input. Yeah, it has one. Look at the circuit diagram. Just connect <i>RAM.CE</i> to A18 (<i>!ROM_CE</i>). When the CPU reads any vector from the first kByte of memory then A18 will be low and the RAM is not enabled. <b><span style="color: #38761d;">Check.✓</span></b><br />
<br />
Next we can suppress the K1 bus control signals in a similar way: As you not yet know they are generated with a 3-to-8 line decoder <span style="color: blue;"><u>74HC138</u></span> which has two negative and one positive enable input. We can connect A19 (<i>!FAST_IO</i>) and <i>!AS</i> to the negative enables, and A18 (<i>!ROM_CE</i>) to the positive enable. <b><span style="color: #38761d;">Check.✓</span></b><br />
<br />
<b>Summary</b>: Yes, we can become <b><span style="color: #990000;">Super-Sinclair</span></b>! We just have only fast I/O with no wait cycles, we'll have the vector table in ROM and we are limited to 128k ROM and 128k RAM and there is a risk of bus collisions if the program accesses forbidden address ranges and there may be regular very short bus collisions between each bus cycle.<br />
<b style="color: #38761d;"><br /></b>
<b style="color: #38761d;">Accepted. </b><b><span style="color: #38761d;">Design finished, let's ship it. ;-) </span></b><b><span style="color: #38761d;">Check</span></b><b><span style="color: #38761d;">✓</span></b><b><span style="color: #38761d;"> Check</span></b><b><span style="color: #38761d;">✓</span></b><b><span style="color: #38761d;"> Check.</span></b><b><span style="color: #38761d;">✓</span></b><br />
<div>
<b><span style="color: #38761d;"><br />
</span></b><br />
<b>Update: </b>For completeness here is the main circuit of the <b><span style="color: #990000;">Super-Sinclair</span></b> design. Of course i won't build it this way, because, as said above, <b><span style="color: #990000;">Super-Sinclair</span></b> means reduced beyond usability.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggGMEHDM9RieP6LTRQkzgztxU0QwFlK0MwjYm2k_x7s0cSSfS94XeWvAkt8FuAvmr99OLraX9ANp2gVUGHvX8fGUunoOSBJDYrQ1bENQ_Fqs5ektgjqYKT5j6i4FSRvXmL0buPaxpGxxg/s1600/super-sinclair-0.2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggGMEHDM9RieP6LTRQkzgztxU0QwFlK0MwjYm2k_x7s0cSSfS94XeWvAkt8FuAvmr99OLraX9ANp2gVUGHvX8fGUunoOSBJDYrQ1bENQ_Fqs5ektgjqYKT5j6i4FSRvXmL0buPaxpGxxg/s1600/super-sinclair-0.2.png" height="472" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Super-Sinclair 68008 Processor Board – no glue logics required</td></tr>
</tbody></table>
<br />
<br />
<br />
<br />
<br />
<br /></div>
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-41488517588338370512014-01-14T18:41:00.001+01:002014-08-13T20:41:22.254+02:00New Project: 68008 MicrocomputerServus,<br />
<br />
one of my weird ideas is to build a microcomputer with every CPU i own. Ok, maybe not really *every*, but some of them i memorize with nostalgia. These are:<br />
<ul><li>Z80 with SRAM</li>
<li>Z80 with DRAM and paged memory</li>
<li>68008, one with SRAM and one with ~ 2MB DRAM SIMMs</li>
<li>68000, let's see</li>
<li>68020, eventually with FPU</li>
<li>68040, with ~ 64MB DRAM PS2-SIMMs probably</li>
</ul>All of them will connect to the <a href="http://k1.spdns.de/Develop/Hardware/K1-Bus/" target="_blank">K1 Peripheral Bus</a>, so that half of the work is already done. ;-) Beyond that, no I/O will be implemented on these boards.<br />
<br />
You see, in essence these are two processors. I started with a ZX Spectrum and proceeded with an Atari ST before i entered the world of Apple, Linux and not Windows.<br />
<div><br />
</div><h3>68008 SRAM Microcomputer</h3>Let's start with the <a href="http://k1.spdns.de/Develop/Hardware/Infomix/ICs%20computer/Microprocessor/68000/68008%20CPU.pdf" target="_blank">68008</a>. I have both, the DIL and the PLCC variant. I'll use the DIL version for the SRAM board and the PLCC version for the DRAM board, because it can address more memory: 4MB instead of 1 MB only.<br />
<br />
The 68008-SRAM board will the half sized – 79x100mm – pretty tight, but it will fit. The 68k CPUs are a little bit nasty to integrate into a system, because they have quite a lot of requirements, especially the 68008 which implements an asynchronous bus model. But i'll use any trick, cheat and simplification i can find to make it fit. :-)<br />
<br />
<h3>Basic Requirements</h3><ul><li>68008 PDIP CPU</li>
<li>Eprom 32 .. 256 kByte</li>
<li>SRAM 128 or 256 kByte</li>
<li>K1-Bus half-sized card</li>
</ul><br />
<h3>Project Page</h3><div><a href="http://k1.spdns.de/Develop/Hardware/K1-Bus%2068008%20CPU%20board%20with%20SRAM/" target="_blank">k1.spdns.de/../K1-Bus 68008 CPU board with SRAM</a></div><div><br />
</div><h3>The Board</h3><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlbZLlKXpp5h0tfklLIVUHzKMoAvRI-N8JrA0dGGE7yi56cs5CoyK0ygLpEL7mtC4CkzDEdUOnrpnrdga-_gTL7O1pnFm6djv4Q_ZPN8N_-EmuFIuI3P6qBTvsjsgqxh9Gm3FTr8ohjkQ/s1600/board+v0.1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlbZLlKXpp5h0tfklLIVUHzKMoAvRI-N8JrA0dGGE7yi56cs5CoyK0ygLpEL7mtC4CkzDEdUOnrpnrdga-_gTL7O1pnFm6djv4Q_ZPN8N_-EmuFIuI3P6qBTvsjsgqxh9Gm3FTr8ohjkQ/s320/board+v0.1.png" height="253" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Layout v0.1 2014-01-14</td></tr>
</tbody></table>To the left is a first layout of the board with all components required for the current circuit.<br />
<br />
The top row ICs are glue logics.<br />
To the left is the K1-bus connector.<br />
The circuits to the left of the CPU connect the CPU to the bus.<br />
The two 74HC573 registers expand the 8 bit bus of the 68008 to the 8 or 16 bit K1-bus.<br />
The 74HC367 hex driver plus some resistors implements the i2c interface.<br />
The 74HC138 decodes the strobe signals for the K1-bus.<br />
In the center of the board is the CPU<br />
and right of it the SRAM and the Eprom.<br />
<br />
<br />
<h3>Requirements and Simplifications</h3>• <b>Memory Map.</b> Memory is divided into 4 sections: RAM, ROM, fast I/O and slow I/O each of which is 256 kByte in size. This limits the size of the RAM and Eprom.<br />
<br />
• <b>CPU Clock</b>. This is generated by a 10 MHz clock module. I avoid the hassle of generating the clock signal "by hand" with a quartz and inverters.<br />
<br />
•<b> CPU Reset.</b> The 68000 family needs <b>0.1s low</b> on <i>Reset</i> and on <i>Halt</i> for power-up initialization. This is currently done with some R and C and a Schmitt Trigger inverter.<br />
<br />
• <b>CPU DTACK.</b> The 68008 needs an acknowledge for every memory read or write access. By delaying this signal you can add wait cycles. By never asserting this signal you can make the CPU hang for ever. This signal will be handled in the most simple way possible: It is tied to ground and this way always asserted. According to some other 68008 projects, where they do this for the test run on a bread board, this should work. Drawback: No wait cycles possible. I'll need a reasonably fast Eprom and SRAM. This also applies to the <i>fast I/O</i>.<br />
<br />
• <b>Bus Error</b>. <i>DTACK</i> is always asserted and <i>BERR</i> is tied to <i>Vcc</i>. There will never be a bus error.<br />
<br />
• <b>Bus arbitration</b>. The K1-bus does not support multiple bus masters and so does this board: bus request <i>BR</i> and bus grant <i>BG</i> are not used.<br />
<br />
• <b>Interrupt control</b>. The 68008 PDIP has two interrupt input lines which can encode 4 states: no interrupt, 2 normal, prioritized interrupts and a non maskable interrupt. The only source for interrupts on this board is the K1-bus and so i need only one normal interrupt. The K1-bus supports prioritized interrupts by enabling/disabling interrupts directly on the attached extension cards.<br />
Now the nasty thing: Devices must provide an interrupt vector during the interrupt acknowledge cycle. An automatic vector can be requested by asserting <i>VPA</i> and so we need to know when a bus cycle is an interrupt acknowledge cycle. For this we must decode the Function Code outputs<i> FC0, 1 and 2</i> which are all '1' during an interrupt acknowledge bus cycle.<br />
<br />
• <b>K1-bus access</b>. As said above there are two address ranges for the K1-bus: fast and slow.<br />
The idea is to use a standard memory cycle for <i>fast I/O</i> where wait cycles are not supported because <i>DTACK</i> is permanently asserted. This is suitable for very fast peripheral cards and for switching <i>interrupts</i> and <i>i2c</i> on the K1-bus.<br />
For slow devices i want to use 6800 peripheral I/O cycles by asserting <i>VPA</i> (valid peripheral address) in this address range. This will do a bus cycle synchronized with the free-running <i>E</i> output of the CPU (which has a fixed period of 10 CPU clock cycles) with at least 11 and at most 18 CPU clock cycles due to synchronizing; and no wait states because of the fixed alignment to the <i>E</i> signal. Eventually i'll come up with something better here.<br />
<br />
• <b>CPU VPA</b>. This input was already discussed in two requirements above: Interrupt control and K1-bus slow access. During an interrupt acknowledge cycle it is pulled low to request an automatic vector (interrupt routine start address) and in slow I/O it is pulled low to request a slow 6800 peripheral bus cycle.<br />
<br />
• <b>K1-bus 16-bit I/O</b>. Peripherals on the K1-bus may use 16 bit I/O. The 68008 has only an 8 bit data bus. There are two possibilities: I use it 'as is' and attach only 8-bit extension cards. Or i add 2 latches to store and receive the upper byte during a 16 bit I/O. I have some K1-bus cards which use the 16 bit bus, most namely the IDE board because IDE is 16 bit wide, and so i'll invest in two <i>'573</i> data latches.<br />
<br />
• <b>K1-bus i2c</b>. Peripheral cards on the K1-bus can have <i>i2c EEproms</i> to signal presence of and identify the card and to provide a universal byte-coded drivers. This costs one <i>'367</i> hex driver IC plus some resistors. This makes it possible to add arbitrary cards to the microcomputer.<br />
<br />
• <b>ROM and RAM</b>. The <i>EPROM</i> and the <i>SRAM</i> may be up to 256 kByte in size each. Due to space constraints only one SRAM IC is possible. Memory access cycles of the CPU are without wait states (see <i>DTACK</i> above) and therefore the memory ICs must be fast enough: Scrutinizing the bus cycle timing charts i expect that 150 ns access time will do it; eventually up to 200 ns will work.<br />
<br />
• <b>System Timer</b>. There is no system timer on the board. Instead it is expected that one of the K1-bus cards supplies one. This is fairly easy, because my serial cards with one (or more) 88C192 dual UARTs can supply this.<br />
<br />
• <b>Serial and Parallel Ports</b>. Any connection to the outer world requires a K1-bus extension card.<br />
<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-72618568036598301122013-02-03T12:05:00.001+01:002014-04-11T22:57:32.371+02:00Version 1.0 of i2c driver EEprom specification<br />
Hello,<br />
<br />
Version 1.0 of the specification for the driver i2c Eproms on the peripheral cards is finished.<br />
<br />
I have also finished translation of the K1-Bus documentation, which was initially written in German.<br />
<br />
Here are the links:<br />
<br />
<span style="font-family: inherit;">K1-Bus documentation: <a href="http://k1.spdns.de/Develop/Hardware/K1-Computer/K1-Bus/" target="_blank">http://k1.spdns.de/.../K1-Bus/</a></span><br />
<span style="font-family: inherit;">Driver EEprom layout and bytecode: <a href="http://k1.spdns.de/Develop/Hardware/K1-Computer/K1-Bus/i2c-eeprom.pdf" target="_blank">http://k1.spdns.de/.../K1-Bus/i2c-eeprom.pdf</a></span><br />
<br />
... Kio !<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-72555782916391119302013-01-21T19:47:00.000+01:002014-04-11T22:58:18.384+02:00K1 Bus UpdateHello,<br />
<br />
after i have worked for some months on my ZX Spectrum emulator, i'm now back for a while to the K1 CPU.<br />
<br />
I worked on the draft for the driver i2c eeproms on the peripherial cards. They are going to version 1.0 soon. In the course i've started translating the K1 bus documentation, which was initially written in German. There is quite a lot of text to translate.<br />
<br />
If you are interested, here are some links:<br />
<br />
<span style="font-family: inherit;">K1 bus documentation: <a href="http://k1.spdns.de/Develop/Hardware/K1-Computer/K1-Bus/" target="_blank">http://k1.spdns.de/.../K1-Bus/</a></span><br />
<span style="font-family: inherit;">Driver eeprom layout and bytecode: <a href="http://k1.spdns.de/Develop/Hardware/K1-Computer/K1-Bus/i2c-eeprom.pdf" target="_blank">http://k1.spdns.de/.../K1-Bus/i2c-eeprom.pdf</a></span><br />
<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-78558075645097460602012-07-18T19:30:00.001+02:002014-01-19T13:30:58.013+01:00XVGA TFT updateHello,<br />
i made some progress with the XVGA controller board.<br />
<br />
<h3>
Current State of the Board </h3>
First, it becomes more expensive, because it had to buy a minimum of 5 of the FPD-Link transmitter chips (note: i sell the others. Interested? ;-). Then the layout is very tight. See here:<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFEpdIZ2clFL7nJY_3WJHIN9ZVU69WgEeJVtAM7W3FTrUb60DxusXHtf-p-hWyaaAziUvDLN-S-JVDQCgdgt62Jf0ZWojU9vpHsGQ6tIT_DZF-lU20i9XnzEaZNmqsKETM9TyOa_QHMno/s1600/2012-07-19+auto+routed+PCB.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFEpdIZ2clFL7nJY_3WJHIN9ZVU69WgEeJVtAM7W3FTrUb60DxusXHtf-p-hWyaaAziUvDLN-S-JVDQCgdgt62Jf0ZWojU9vpHsGQ6tIT_DZF-lU20i9XnzEaZNmqsKETM9TyOa_QHMno/s320/2012-07-19+auto+routed+PCB.png" height="213" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">2012-07-18 autorouted board</td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
ICs placement is nearly final, then i'll add some more hand-routed wires, auto-route again and then hand-optimize. This will take a week or two.<br />
I had real problems with the rams and FPD-link controller, they actually <i>just</i> fit between the '245 bus transceivers and the VGA connector. I tested a couple of arangements, but this produced the least vias.<br />
FYI: bottom left is the 16 bit K1 bus, directly above two 74245 bus transceivers, the SMD ICs are RAM and the FPD-Link transmitter. 6 chips next to the right are drivers and drivers with latches, which are used to select between an externally supplied address (for the CPU reading/writing the video RAM) or internal address from the counter cascade, used to address the video RAM for display. Next 'column' of chips are the external address registers/counters, next are the internal address counter cascade, the vertical chips at the right are clock and ATtiny. Bottom right 6 ICs are the control logic. There's an I2C EEPROM sitting on the rear side of the PCB underneath the bus connector.<br />
Though i us a 15-pin VGA SUB-D connector, the signal is not VGA but transmits 4 LVDS signal lanes, each 3 wires: pos. and neg. differental signals and associated GND. In addition one PWM signal is transmitted on pin 15 which will control the LCD backlight brightnes. According to what i found in the net this is a 5V 125kHz PWM signal.<br />
<br />
<h3>
Current Circuit</h3>
Here's an update to the circuit as well:<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTwenhCZg3KqBUTDQpJUiqNlnV2DWVnSzuE4EWSxgYNUJweZYHHM2nVZ78oafffAv9KgEXe85-Tvx8kC5B1_pNNpDaLi9GHS2q4qB4H5GrIwYvSqXTUMp__f5iEqXf9YZXDLjM0SyobCU/s1600/2012-07-18-1.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTwenhCZg3KqBUTDQpJUiqNlnV2DWVnSzuE4EWSxgYNUJweZYHHM2nVZ78oafffAv9KgEXe85-Tvx8kC5B1_pNNpDaLi9GHS2q4qB4H5GrIwYvSqXTUMp__f5iEqXf9YZXDLjM0SyobCU/s320/2012-07-18-1.png" height="176" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Circuit 2012-07-18 - Data Paths</td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMaDZ7mV9wWjPwdYLcWuEST54M-qXT2J2DDP_aNpSSTJ9tb3b9kv9trNu-0jn4UW9jm_VIEf6QUdaSWr5wx_kZ7Uh6uUX8IkpnfqJGjd6dfeplLMZtw15q1oofq59CIiHIqXc8mTqMW3M/s1600/2012-07-18-2.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMaDZ7mV9wWjPwdYLcWuEST54M-qXT2J2DDP_aNpSSTJ9tb3b9kv9trNu-0jn4UW9jm_VIEf6QUdaSWr5wx_kZ7Uh6uUX8IkpnfqJGjd6dfeplLMZtw15q1oofq59CIiHIqXc8mTqMW3M/s320/2012-07-18-2.png" height="183" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Circuit 2012-07-18 - Control Logics</td></tr>
</tbody></table>
<br />
<br />
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-83494436756502592862012-07-04T12:36:00.002+02:002014-04-11T22:58:58.787+02:00XVGA TFTThough i should finish the built LCDs first, i've already begun with 3rd display. I's a 1024x768 pixel TFT from my old iBook. It has a LVDS FPD-Link connection and i have searched the web for info about the panel and FPD-Link. I think i've got enough info to build it.<br />
<h3> Major problems:</h3>I need a special transmitter chip, preferably in 5V. These chips are generally hard to find (never used by hobbyists) and 5V is even harder. But i'll get a quote today. :-)<br />
Timing is at the upper end of any hobbyists project: Pixel clock is 65 MHz, may be eventually lowered down to ~62 MHz.<br />
This requires at least 15ns RAM, which will result in very tight timing, or better 12ns. And i need 1.5 MByte of it. Though i have plenty of RAM in stock, i opted to buy three 256Kx16Bit 12ns RAMs. Head count of ICs on the PCB is already very high.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmexA2UhJg8mNpayriuXpyZ0J3Fut4m5_sEoS2DkstT2JrG7BJTtH6WHZQdRAtg15bbQ2rL9at1yhO7ppHR0AJyvcG37Nj8dBWyKd8aKpRDsIfYKT1-aEkDmJ5rrd3c6YI_AYrseTBbiY/s1600/vga-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmexA2UhJg8mNpayriuXpyZ0J3Fut4m5_sEoS2DkstT2JrG7BJTtH6WHZQdRAtg15bbQ2rL9at1yhO7ppHR0AJyvcG37Nj8dBWyKd8aKpRDsIfYKT1-aEkDmJ5rrd3c6YI_AYrseTBbiY/s200/vga-1.png" height="127" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Data flow on the XVGA controller</td><td class="tr-caption" style="text-align: center;"><br />
</td></tr>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlM3J6zcD-RwiPgTmEwNFiTgAz4mwZWizZABJ32xl_xb3RgJW02kBmRsxqwB_f9UOzqxM7U_gEd8fXvnFytiJypGSBxwqEQ8byx95CPFsYHU80U1Tw5PjKNp7VoUdj_GBZGd6NDKEsixI/s1600/vga-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlM3J6zcD-RwiPgTmEwNFiTgAz4mwZWizZABJ32xl_xb3RgJW02kBmRsxqwB_f9UOzqxM7U_gEd8fXvnFytiJypGSBxwqEQ8byx95CPFsYHU80U1Tw5PjKNp7VoUdj_GBZGd6NDKEsixI/s200/vga-2.png" height="156" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Control signals</td></tr>
</tbody></table><br />
<h3> Project Page </h3>The project page is <a href="http://k1.spdns.de/Develop/Hardware/K1-Computer/IO-Boards/VGA/" target="_blank">.../IO-Boards/VGA/</a> on my home site. This is on my private computer and everything i do here is directly visible on this page. Currently it contains a collection of spec sheets and the current state of the controller board design.<br />
<br />
<br />
<h3> The Plan</h3>The design ideas are as follows:<br />
• The VRAM is addressed by a 20 bit counter cascade. Due to timing problems, the address is buffered by a set of 74574 latches, so the address is always one clock cycle delayed. The RAM output data is directly fed into the FPD-Link transmitter, which is clocked by the same clock signal. All running on 64MHz with a clock cycle of ~15ns.<br />
• The slow signals, VSYNC, HSYNC and DE (Display Enable) are generated by an ATtiny. It also controls count enable of the address counters, to stop them during HSYNC and VSYNC (or, when DE is false). The ATtiny will be clocked with 16 MHz synchronously with the 64MHz pixel clock.<br />
The ATtiny will also generate the FFB (frame fly back) interrupt signal, which is very important:<br />
• VRAM access from the CPU will be completely asynchronously with the pixel access for the display. It will simply override the signals for the display, resulting in 'snow'. Each access will 'destroy' the display of approx. 3 pixels. This allows me accessing the VRAM without asserting the !WAIT signal on the bus. I have already checked the timing, writing is safe, reading is tight, but should work.<br />
Accessing the VRAM requires sending an address and then one data i/o. The address is 20 bit, so it has to be transferred in two chunks. I opted to split the address in two 10 bit packages, which will directly translate into X and Y pixel address. To reduce the required bus transfers, i designed the address registers as counters as well. They will provide an auto-increment feature, so that i only need to set the start address and then can read or write in burst mode, hopefully with the full bandwidth of the bus of 16Mwords/sec. The X address can auto-increment, the Y address can auto-decrement as well. I probably can't make the X address easily auto-decrement, because i simply have not enough control lines to control this easily. The 'control lines' are the bus's address lines, and it has 6 of them.<br />
To avoid the 'snow' effect when accessing the VRAM, i plan to do most i/o during the vertical frame flyback, which may be up to 10% of the total frame time. The exact maximum number of lines during ffb of my display will be determined when it is all built, therefore it's nice to have it programmable, because it's done by the ATtiny. It will be slightly tricky to align the control signals of the ATtiny with the 4-pixel boundary (ATtiny clock is Pixel clock ÷ 4) because the DE (display enable) signal for the FPD transmitter and the count enable signal for the address counter must not start and stop somewhere in the middle of a 4-pixel package but exactly at the start or end. Else the image on the TFT will be shifted some pixels, missing some at the left side and displaying garbage at the right side.<br />
<br />
Let's see how it all works!Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-14180537936124793552012-06-27T19:06:00.001+02:002014-01-19T13:29:55.549+01:00The K1-16/16 CPU<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIpbowp_hX10Z_wK8-PqvnEVHfLE9Z6YGot8QFQrghfY90N-rXAnsDh1p7WMeAKY49o9TkAg1FqaKsnhpnokT-CPCrhWUJNHA_9M4MSU7yYQ9rvqjSDq9_iX4lEeFQQNHfq5RU6DyKOfo/s1600/cpu-2010-02.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIpbowp_hX10Z_wK8-PqvnEVHfLE9Z6YGot8QFQrghfY90N-rXAnsDh1p7WMeAKY49o9TkAg1FqaKsnhpnokT-CPCrhWUJNHA_9M4MSU7yYQ9rvqjSDq9_iX4lEeFQQNHfq5RU6DyKOfo/s1600/cpu-2010-02.jpg" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The self-built K1-16/16 CPU, built with standard 74xx CMOS ICs</td><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
<br />
The K1-16/16 CPU is the heart of the self-designed and home-built K1-16/16 Computer.<br />
It is built with CMOS ICs from the 74AC series and fits on 5 Euro boards (160 x 100 mm).<br />
<br />
<h4 class="i">
Sometimes you are struck by an idea...</h4>
Due to depressions programming became harder and harder. So i thought, why don't do something more simple, with more manual work? Electronics, for instance. And, thanks to the internet, i have already read from other maniacs, who built a 6502 CPU. Or a Z80 in FPGA. Or Dennis Kuschel's <a href="http://www.mycpu.eu/" target="_blank">myCPU</a>. And there's a web ring about it. If others can do this, it can't be that hard. Basically...<br />
Of course my CPU should be Different. Better. And Simple, so that i can understand it myself. <b>B-)</b><br />
For symmetry i settled with a 16/16 bit design: 16 data bits and 16 address bits.<br />
<br />
<h3>
Unusual and Generally Interesting Parameters</h3>
<div style="background-color: #f3f3f3;">
• Combined <b>Harvard</b> and <b>Von Neumann</b> architecture</div>
<div class="white" style="background-color: #f3f3f3;">
• <b>16 MHz</b> system clock<br />
Front panel with slow motion clock for exhibitions et. al.<br />
Full static design down to 0 Hz<br />
• <b>16 bit</b> internal data bus<br />
• <b>16 bit</b> internal address bus<br />
• 64k x 16 bit <b>internal ram</b><br />
• 32k x 24 bit <b>microcode</b><br />
organized as 2 code planes à 16k for conditional execution and branching.<br />
the microcode is copied from eproms to rams during boot for increased speed.<br />
it is also possible to load the microcode from an <b>external</b> source instead.<br />
the microcode implements:<br />
boot code, BIOS, kernel<br />
100++ assembler opcodes for ram-based programs<br />
100++ <b>millicode</b> opcodes for microcode-based forth or c-style programs<br />
• No flag register. (but flags)<br />
• Built with <b>discrete logics</b> using <b>74HCxx</b> and <b>74ACxx</b> ICs<br />
CPU fits on 5 "Euro" printed circuit boards (160 x 100mm)<br />
• <b>Manual</b> circuit design<br />
Manual routing of the PCBs (with EagleCAD)<br />
Professional made double-layer circuit boards</div>
<h4>
Harvard Architecture </h4>
Programs can be written directly in microcode. Adopting this view, the K1 CPU has separated program and data memory. This is the <a href="http://en.wikipedia.org/wiki/Harvard_architecture" target="_blank">Harvard Architecture</a>.<br />
<h4>
Von Neumann Architecture</h4>
More likely, the CPU can also use a fixed microcode, which reads opcodes from the ram and executes them. Seen this way it has a combined program and data memory. This is the <a href="http://en.wikipedia.org/wiki/Von_Neumann_architecture" target="_blank">Von Neumann Architecture</a>.<br />
<br />Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-90924511343358470922012-06-27T18:13:00.000+02:002014-04-11T22:59:53.393+02:00Start on blogger.comHello,<br />
I'm building a CPU for 4 years now (more or less) and accompanied this on my home page <a href="http://k1.spdns.de/Develop/Hardware/K1-Computer/K1-CPU/" target="_blank">k1.spdns.de</a>. This worked quite well but i wanted to separate the blog from the project documentation itself and i wanted to enable some feed back. So i started this blog on blogger.com. I will move some stuff in here which previously was on my website; i'll see whether i can fix the dates.<br />
<br />
... Kio !<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-46989097727139101652012-06-12T00:00:00.000+02:002014-04-11T23:00:28.611+02:002nd Display<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0SYdIc0Co63ASWstu0lxtyVLYP_pmd4_c3lKzCxpPf4yaYDdqWdbRk8wVdkc1_lzRa1okppvFuesjv1KV-BeqXu_mBVkL9Pt3EECxBecLfPgt_lMzRmnANVR7I5-LH1BGNPqPjCe_6_0/s1600/lcd-2.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0SYdIc0Co63ASWstu0lxtyVLYP_pmd4_c3lKzCxpPf4yaYDdqWdbRk8wVdkc1_lzRa1okppvFuesjv1KV-BeqXu_mBVkL9Pt3EECxBecLfPgt_lMzRmnANVR7I5-LH1BGNPqPjCe_6_0/s400/lcd-2.jpg" height="400" width="400" /></a></div>Going into mass production. <b>;-)</b> I built a second, very similar LCD display which uses the same controller board. This one has a backlight, but it was CCFL. I had no inverter and building one and adapting it to the CCFL wold have taken too long and so i replaced it with an array of LEDs. Not good but working. See the photos on the <a href="http://k1.spdns.de/Develop/Hardware/Projekte/LM64K101%20-%20LCD%20Display%20640x480" target="_blank">LM64K101 - LCD Display 640x480</a> project page. Next is to debug the terminal software a little bit more and use it as output for the computer.<br />
Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0tag:blogger.com,1999:blog-1984932124087943660.post-68868690985994764392012-05-26T00:00:00.000+02:002014-04-11T23:01:15.491+02:00Debugging the LCD Display Driver and Hardware<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtx0I_uS37CDDyEPzSHnQRnGkmPF3WbsxcKzxzRK45EPyniLrt6TSRj6yPQLAo1zEv2pdiOqxfxXFFKPCoJz7yo1tZo0emeLo_BhB3IzRjmcVi3vLzwp9y7Idk7R_XUbmspedpi079FHc/s1600/lcd-1.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><br />
<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtx0I_uS37CDDyEPzSHnQRnGkmPF3WbsxcKzxzRK45EPyniLrt6TSRj6yPQLAo1zEv2pdiOqxfxXFFKPCoJz7yo1tZo0emeLo_BhB3IzRjmcVi3vLzwp9y7Idk7R_XUbmspedpi079FHc/s400/lcd-1.jpg" height="400" width="400" /></a></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">This week i worked on the <a href="http://k1.spdns.de/Develop/Hardware/Projekte/LM641541%20-%20LCD%20Display%20640x480" target="_blank">640x480 pixel b&w LCD terminal</a>. Soldering was easy, but fixing all the bugs took some time. I also had to do some changes to the terminal code because i realized that i was using the LCD upside down.</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">I connected the LCD and powered the board through the programming header. Off course nothing worked, except for the display refresh routine, which brought up a picture of the erased DRAM cells. Step by step i brought up more functions: Erase screen, print characters, read and write whole pixel lines and scrolling. I had to add some nops to the DRAM read and write timing, because the data goes through series resistors which create some delay. For the next board i'll reduce them slightly. Then printing of standard-size characters with 4 attributes in all combinations works.</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZH4uGSlt6Uioy2FVgeyKhPAEdNmJihIx723rgb8HVxYcJxvLdTBi_XAgraFq8ULgmDXJM9ZCjmjo_xOd6KRaKeCmCHyT4dzYIyg3EhWHaYY88y3mgDW-b7FHgjEOQW7y5OELCL5ldG6g/s1600/lcd_fixed.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZH4uGSlt6Uioy2FVgeyKhPAEdNmJihIx723rgb8HVxYcJxvLdTBi_XAgraFq8ULgmDXJM9ZCjmjo_xOd6KRaKeCmCHyT4dzYIyg3EhWHaYY88y3mgDW-b7FHgjEOQW7y5OELCL5ldG6g/s320/lcd_fixed.jpg" height="320" width="320" /></a></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"> Finally one last important step: Attach it via serial line to USB to my Mac. Nothing worked. I adjusted the Baudrate on both sides. I printed text from the LCD terminal on the serial line in an endless loop. There was no signal on the TxD line. Why? But there seemed to be a signal on the RxD handshake line. ... ???</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><br />
</div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">I had connected data lines to handshake and handshake to data lines on the board. <b>:-(</b>. Fixed it with a cutter, solder and wire. Tested. Worked. <b>:-)</b></div><div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"><b><br />
</b></div>Anonymoushttp://www.blogger.com/profile/17460730281415132574noreply@blogger.com0