Author Topic: Z80 Homebrew Computer - fault finding  (Read 96314 times)

0 Members and 1 Guest are viewing this topic.

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #400 on: August 19, 2017, 04:18:04 pm »
OK - seems the CTC is working as I'm able to reset the SBC after a predetermined time.  The problem is I'm not trying to reset it, I'm trying to print a '.' every time the interrupt is serviced!  |O

I think my understanding of how the interrupt vector is passed to the CTC on Channel 0 is a little lacking.  :(

I was following an example where the interrupt vector table was at $20 and the vector passed to Ch0 was 10h.  Problem I've got is that I can't put my vector table there as it's already occupied, so I went for $24 and passed 18h as the vector.  That's obviously incorrect as, instead of printing a full-stop every time the interrupt is called, the SBC just resets.  I'm making a silly error somewhere, but I'm not sure where...  :-//

Here's some of the code I'm using:

Code: [Select]
;------------------------------------------------------------------------------
; CTC Vector = 0x24
;------------------------------------------------------------------------------
.ORG  $0024
.DW CTC_Int

;------------------------------------------------------------------------------
;   Initialise CTC
;------------------------------------------------------------------------------
INIT_CTC:
LD A,00000011b ; int off, timer on, prescaler=16, don't care
; ext. TRG edge, start timer on loading constant,
; no time constant follows, sw-rst active, this
; is a control command
OUT (CTC_0),A ; Channel 0 is on hold now
OUT (CTC_1),A ; Channel 1 is on hold now
OUT (CTC_2),A ; Channel 2 is on hold now
OUT (CTC_3),A ; Channel 3 is on hold now


; Set up the interrupt vector in Channel 0
LD A,18h ; int vector defined in bit 7-3, bit 2-1 don't care,
; bit 0 = 0 (for vector)
OUT (CTC_0),A ; and loaded into channel 0

; Interrupt code
CTC_Int: PUSH AF
PUSH HL

; CTC test routine - just print a . to the command line
LD A,'.'
CALL TXA

POP HL
POP AF
EI
RETI


What am I (obviously) doing wrong?
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #401 on: August 19, 2017, 05:26:13 pm »

First break it apart.

You need to initialize the chip. Not in interrupt code.

Then You talk to CTC to setup a channel like you want.
And
Process interrupts.

You almost need to think that Interrupt code is a separate computer.
You need to be careful of what code the interrupt code uses.

For example
Main code could be in process of adding a character to output buffer when the interrupt happens. Both sets of code could write to same location and you lose a character.


Good interrupt code passes data in memory.
Interrupt code writes data and main code only reads.
Main code writes data and interrupt code only reads.


Question #1
   How many different interrupt vectors does the CTC use?

Question #2 Why put new code in mess?
Vectors go up to 127


With Vector interrupts the Z80 uses a table in memory of the starting address of each vector

The I register is the High byte address of the table
The vector from device is low byte of table

If I = ____ then
at
ORG (I value) 00H is vector zero

Each vector is a .DW

Grant by using I = 0 is making things harder

If memory serves the SIO vector is at 60
Easy thing to do is to put CTC vector just above vectors the SIO needs Or just below the SIO by the number of vectors the CTC needs.
A table with all vectors in a group.


So in your code you have an interrupt table

: Interrupt table
Org _____

.DW SIO_interrupt 0 : vector 60
.DW SIO_interrupt 1 : vector 62
.DW SIO_interrupt 2 : vector 64
.DW SIO_interrupt 3 : vector 66
.DW SIO_interrupt 4 : vector 68
.DW SIO_interrupt 5 : vector 6A
.DW SIO_interrupt 6 : vector 6C
.DW SIO_interrupt 7 : vector 70
.DW CTC_interrupt 0 : vector 72
.DW CTC_interrupt 1 : vector 74
.DW CTC_interrupt 2 : vector 76
.DW CTC_interrupt 3 : vector 78

Need to know how many interrupts SIO and CTC can use and adjust this.
Note that the actual interrupt code can be anywhere in memory





« Last Edit: August 19, 2017, 08:11:33 pm by C »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #402 on: August 19, 2017, 05:29:21 pm »
Yeah, the code I pasted isn't how it's presented in the assembly - I just pasted the relevant parts into one block for the forum post.  It's just the vector I'm having trouble with - I've clearly misunderstood how the interrupt address is put together.  My interrupt table is at $24, but passing 18h as the vector isn't directing the CTC to the correct location in memory.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #403 on: August 19, 2017, 05:39:02 pm »

Think you are reading things wrong
With Grants code
I = 0H

So the interrupt table starts at 0000h
The Table is 256 bytes in size.

When a Interrupt happens The Z80 reads the vector at interrupt ACK

The Z80 then uses the I register value as the high byte of a memory access.
The Vector read is the low byte of a memory access.
The Z80 reads a word at that address and does you might think of as a Call instruction with the RetI as a return from sub.

Grant is cheating and putting some code in areas where the vectors are not used as vectors.

 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #404 on: August 19, 2017, 07:15:33 pm »
Hmmm... okay, must admit to being a bit confused by all this at the moment.  :-//

Here's the start of the monitor code as it stands, from 0000H effectively:

Code: [Select]
MON .ORG $0000 ; MONITOR ROM RESET VECTOR
;------------------------------------------------------------------------------
; Reset
;------------------------------------------------------------------------------
RST00 DI ;Disable INTerrupts
JP MINIT ;Initialize Hardware and go
NOP
NOP
NOP
NOP
;------------------------------------------------------------------------------
; TX a character over RS232 wait for TXDONE first.
;------------------------------------------------------------------------------
RST08 JP conout
NOP
NOP
NOP
NOP
NOP
;------------------------------------------------------------------------------
; RX a character from buffer wait until char ready.
;------------------------------------------------------------------------------
RST10 JP conin
NOP
NOP
NOP
NOP
NOP
;------------------------------------------------------------------------------
; Check input buffer status
;------------------------------------------------------------------------------
RST18 JP CKINCHAR
NOP
NOP
NOP
NOP
NOP

;------------------------------------------------------------------------------
; CTC Vector = 0x24
;------------------------------------------------------------------------------
.ORG $0024
.DW CTC_Int

;------------------------------------------------------------------------------
; SIO Vector = 0x60
;------------------------------------------------------------------------------
.ORG $0060
.DW serialInt

I inserted the CTC interrupt vector (table?) before the SIO vector that Grant made, following what he's done as I don't really know what I'm doing.  ;)

Originally I added the 5 NOPs after RST18 (they aren't there in Grant's original code) thinking that I could just put  the .DW after them, but then thought that explicitly setting the address via an ORG statement would be better.  I chose $24 as it's in an unused part of the ROM and $24 only has bits set in bits 7-3, which seem to be the only bits the user can set if I'm reading the Z80 Peripherals User Manual properly (almost certainly not though!)

So... the vector 18h appears incorrect for the code above.  What should I use instead to get the Z80 to call CTC_Int?
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #405 on: August 19, 2017, 07:45:59 pm »
Looking at Grant's Monitor.asm

It is a mess to add code to.
One programming error leads to a big mess.
Just not good programming practice for a Z80

These should all be in source
:RST 0  ,org 00h
:RST 08  ,org 08h
:RST 10  ,org 10h
:RST 18  ,org 18h
:RST 20  ,org 20h
:RST 28  ,org 28h
:RST 30  ,org 30h
:RST 38  ,org 38h

All it takes is a typo in source to start running code at these addresses.
As these act like a call instruction, an error message followed by a RET should be in place of unused RST

In addition should be notes or entries for other interrupt mode addresses.
Interrupt mode 1 starts at 38H
Nonmaskable Interrupt starts at 66H

Look at an Assembly listing printout
what instruction is at 66H
what will happen if you start running code from 66H

So
My read of  CTC, It uses 4 interrupt vectors.
Nice to have all interrupt vectors in a group, so
60H - 8 is CTC channel 0 Vector in table
60H -6 is CTC channel 1 Vector in table
60H -4 is CTC channel 2 Vector in table
60H -2 is CTC channel 3 Vector in table

So
.org 58H
.Dw      : channel 0 vector
.Dw.
.Dw
.Dw
.Dw        : SIO vector located at 6


Code: [Select]
:  Interrupt vector table starting at Vector 58
  .ORG $0058
; CTC channel 0 Vector in table
.DW CTC_ch0
; CTC channel 1 Vector in table
.DW CTC_ch1
; CTC channel 2 Vector in table
.DW CTC_ch2
; CTC channel 3 Vector in table
.DW CTC_ch3
;------------------------------------------------------------------------------
; SIO Vector = 0x60
;------------------------------------------------------------------------------


.DW serialInt

; Start of :NMI interrupt
.org 66

.org 70H
;------------------------------------------------------------------------------
; Serial interrupt handlers
; Same interrupt called if either of the inputs receives a character
; so need to check the status of each SIO input.
;------------------------------------------------------------------------------
serialInt: PUSH AF

Program the CTC to use vector 58H for channel 0


 


 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #406 on: August 19, 2017, 08:50:01 pm »
Yeah, the code I pasted isn't how it's presented in the assembly - I just pasted the relevant parts into one block for the forum post.  It's just the vector I'm having trouble with - I've clearly misunderstood how the interrupt address is put together.  My interrupt table is at $24, but passing 18h as the vector isn't directing the CTC to the correct location in memory.

What you state here is not correct
Your interrupt table is not at $24

Grant sets the I register to 0H, so the interrupt table starts at 0000H
Note that if you set the I register to 01H then the interrupt table would start at 0100H.

What you are trying to do is add or change a vector in the table.
The Interrupt table is an array with a size of 256 bytes of 16-bit integers.
The index of this array goes from 0-127 or 00H to FEH by words.
Each of the 16-bit integers is a starting location for interrupt code.
In C this would be a Pointer to Code.

In assembly language for a complete Interrupt table, You have 128
.DW entries with the data being interrupt code starting addresses.
If you can guarantee that a vector will go un-used then the two bytes of that vector can be used for other purposes like storing data or program code.

 


You should note that when the Z80 does an INT_ACK cycle, it expects D0 to be Zero for a vector.
For Most or all Z80 IO chips you program the Vector in the upper 7-bits. Some or all have the capability to create more then one vector and modify the lower bits of the programmed vector leaving D0 as Zero and the upper bits unchanged..
The CTC with four timer channels uses four vectors. This lets interrupt code be simple and just process one channel's interrupt needs. So D1 & D2 in vector are the Channel.


 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #407 on: August 19, 2017, 09:42:11 pm »
Thanks for your help with this, C - it's clear that Grant's code isn't the best starting point for learning about interrupt tables.  Can you suggest any sites, books or other resources that would be a good place for me to read up on this (aimed at beginners of assembly/Z80 programming ideally?)
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #408 on: August 19, 2017, 10:27:34 pm »
Most of the beginning assembly language books I know of are
1. For a computer like the TRS-80 that has a rom and shows the Assembly using a lot of ROM code.
2. For a system like CP/M

In both cases little about Interrupts are not mentioned.

I would lean towards you taking control of all the source you have and making it better. In the process you would gain an understanding of how the system works making it easer to do your thing.

For example
I think you are burning new roms to test your code changes.
You said you got CP/M working.
You can edit, assemble and run programs on CP/M
Would not need to burn code.

Even with the boot roms in place with some small changes you could run your new code and test it.

Problem is grant's whole thing is a mess.  Learn this and then forget most of it with a new change.
Think of what you have done. Build a  basic computer using an overclocked serial chip for a different microprocessor family. then scrap it and switch to the SIO.
Grant's programming is the same. What you learn about Monitor.asm helps little when you shift to CP/M. No great need to make you jump through hoops.

So You are trying to hack on to a mess. This makes it much harder for you while saving little programming space.

You are really trying to write not beginner code and Grant's mess makes it harder.

Stage one of gaining control of this.
You need assembly printout listings of grant's code.
 For you to play with interrupts easy, you need the Interrupt table in ram.
The easy place would be to put Interrupt table at top of rem.
Grant does this with his Cbios but then clutters it up with code and data just like he does in the monitor rom.

So want to make it easer for you and take control of grant's code and fix it?
 
 .
 
 

« Last Edit: August 19, 2017, 10:30:06 pm by C »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #409 on: August 20, 2017, 09:16:23 am »
I would lean towards you taking control of all the source you have and making it better. In the process you would gain an understanding of how the system works making it easer to do your thing.

Yes, that's exactly what I've been doing, though the process is a little more difficult as I'm learning assembly at the same time as improving the existing code.  :o

For example
I think you are burning new roms to test your code changes.
You said you got CP/M working.
You can edit, assemble and run programs on CP/M
Would not need to burn code.

Even with the boot roms in place with some small changes you could run your new code and test it.

Yes, I'm using an EEPROM for the ROM so I'm able to make changes to the code very quickly (<60 seconds from source compile to SBC switch-on).  I've learned an awful lot from modifying Grant's monitor code though and have a monitor that functions more like a BASIC interpreter now (albeit without indirect mode) with a full CLI and custom commands for viewing and editing memory locations individually or en-masse to aid me with my assembly learning.

I would like to start learning more about CPM though - obviously the hardware side has been top of my priority list currently, but you're right I'm itching to get into CPM and start writing software for it.

You are really trying to write not beginner code and Grant's mess makes it harder.

Stage one of gaining control of this.
You need assembly printout listings of grant's code.
 For you to play with interrupts easy, you need the Interrupt table in ram.
The easy place would be to put Interrupt table at top of rem.
Grant does this with his Cbios but then clutters it up with code and data just like he does in the monitor rom.

So want to make it easer for you and take control of grant's code and fix it?

Yep, definitely.   :-+

As the CTC is working nicely now, my next step is to write a system clock (similar to the old IBM XT/AT MS-DOS one that asks you for the time when you turn it on) which won't take long (I'll use the interrupt to increment 16-bit value in a memory location every second, then have a CLI command read that value and translate it into a human-readable time to show the user time since switch-on) then start working on re-integrating the PSG again (it's going to be rebuilt as I'm going to use an AY-3-8910 for the extra IO port as I'm having to use a larger breadboard for the interface and delay logic that grumpydoc has created - thanks grumpydoc  :-+) and getting the synth software working now that I've got an internal clock to call the waveform generation routines frequently.   ^-^
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #410 on: August 20, 2017, 11:30:05 am »
What Ram and eeprom are you using now?


For CPM

I liked wordstar as my editor. could make documents and write source code with it.

There are many Assemblers
  Some are relocating macro assemblers.

From microsoft there was M80 assembler
L80 is a linker so you can link different assemblys together.
many others.

You could do all your programming & testing on the Z80.

Now If you can modify Cbios you could get CP/M3 running and have a larger space for programs.
You could also modify Cbios and get turbodos running. This is a networking system
Both CP/m3 & turbodos want more memory.

---------------------------
In monitor rom
you have capability of download of intel hex format programs.
You just write your programs so they exist in ram.
ORG 4000h I think is your ram start location.

If you modify your hardware
  You could have writable ram starting at 0H with reads from eeprom at boot.  A simple program could then read from rom and write back to same address making a copy of eeprom in ram.  You could then switch reads to come from ram.
The programs you are writing could then modify ram when needed.
A 74xx273 is the chip to use for this.

I would not mess with PSG for IO ports, You can do a Port with a 374 very easy.
This would be a faster port then PSG with nothing but an IN or OUT required for software.
If you want or need interrupts for an IO port a PIO would be best choice. A 8255 will also work but will need help for interrupts.


monitor.asm
As long as monitor.asm code does not go up to 2000H you should be fine.

You can change the SIO vector with little problems
Do following
1. put an .org 100 before serialInt.  The serial int code will now start higher at 100.
    This change will not effect anything  but leave more unused space before this code.

2. With NMI starting at 66h, would be smart to use vectors higher then this so that future NMI code will have some space.
    Need to make two changes in code to keep SIO interrupt vector working
     A. change the vector you write to SIO
     B. Position the
          "DW serialInt" at vector address.
  If you write F0H to SIO as a vector address the above DW is at 00F0H
  If you write 80H to SIO as a vector address the above DW is at 0080H
That is all there is too it.

Note that you can change the I regester which moves the interrupt vector table.
  If you write F0H to SIO as a vector address the above DW is at (I register value)F0H
  If you write 80H to SIO as a vector address the above DW is at (I register value)80H
If i = 2 then example for vector F0H above DW is at 02F0H

Now I am not a fan of PSG.
But how you write your program can make a big difference.

Look at grant's "initialixe SIO" code.
This is simple code but hard to change using a program. If the data is in a table then much easer to change

This is the data sent to SIOA_C
00H.18H,04H,C4H,01H,18H.03H,E1H.05H,RTS_LOW,

Code just needs to output these bytes to the port.
You could have a byte that specifys the number of bytes
Z80 has an instruction to do this easy.

When you go to programming your PSG having data separate from code would make things easer.

This is using a CPU for what it is good at, processing data.

 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #411 on: August 20, 2017, 07:44:05 pm »
What Ram and eeprom are you using now?

For the ROM I'm using a 39SF010A and the RAM is an AS6C1008-55PCN.

Now If you can modify Cbios you could get CP/M3 running and have a larger space for programs.
You could also modify Cbios and get turbodos running. This is a networking system
Both CP/m3 & turbodos want more memory.

Yes, I'd like to upgrade to CP/M 3 but haven't even started looking at where to get it from, let alone its system requirements etc. yet. Still working on (and learning) the hardware currently.

In monitor rom
you have capability of download of intel hex format programs.
You just write your programs so they exist in ram.
ORG 4000h I think is your ram start location.

Yes, I'm using (a slightly modified version of) Grant's Intel Hex Loader routine, so I can load hex files anywhere in memory easily and execute code anywhere in RAM from my monitor CLI using a CALL command.

I would not mess with PSG for IO ports, You can do a Port with a 374 very easy.
This would be a faster port then PSG with nothing but an IN or OUT required for software.
If you want or need interrupts for an IO port a PIO would be best choice. A 8255 will also work but will need help for interrupts.

Well, I want to add sound capabilities to my SBC with an AY-3-891x, so I may as well make use of the IO port/s it provides.  I have a 4MHz PIO, that will likely be the next thing I'll add once the PSG is up and running.

You can change the SIO vector with little problems
Do following
1. put an .org 100 before serialInt.  The serial int code will now start higher at 100.
    This change will not effect anything  but leave more unused space before this code.

2. With NMI starting at 66h, would be smart to use vectors higher then this so that future NMI code will have some space.
    Need to make two changes in code to keep SIO interrupt vector working
     A. change the vector you write to SIO
     B. Position the
          "DW serialInt" at vector address.
  If you write F0H to SIO as a vector address the above DW is at 00F0H
  If you write 80H to SIO as a vector address the above DW is at 0080H
That is all there is too it.

Yes, I didn't realise the vector addressing was that simple.  When I was putting the CTC interrupt vector at $24 and writing 18H to it as the vector address, that was because the example I was following did something similar.  Didn't realise it was as easy as ORGing the interrupt at an address and writing that same address to the CTC as a vector.

Note that you can change the I regester which moves the interrupt vector table.
  If you write F0H to SIO as a vector address the above DW is at (I register value)F0H
  If you write 80H to SIO as a vector address the above DW is at (I register value)80H
If i = 2 then example for vector F0H above DW is at 02F0H

Yes, got that the I register holds the MSB for the vector table addresses.  So I could just copy the vector table to a place in RAM, say A000h, and modify the I register to hold A0h and hey presto! the vectors are moved into writable RAM?

Look at grant's "initialixe SIO" code.
This is simple code but hard to change using a program. If the data is in a table then much easer to change

This is the data sent to SIOA_C
00H.18H,04H,C4H,01H,18H.03H,E1H.05H,RTS_LOW,

Code just needs to output these bytes to the port.
You could have a byte that specifys the number of bytes
Z80 has an instruction to do this easy.

Not so good for code commenting and readability though?  ;)

When you go to programming your PSG having data separate from code would make things easer.

This is using a CPU for what it is good at, processing data.

Absolutely.  I have some libraries for the AY that I'm going to be implementing which are based more on modern OOP programming than 80's assembly, much better code than Grant's monitor code.  I've written the interface to link the libraries to my specific hardware, I just need to rebuild the PSG circuitry on the larger breadboard so there's room for grumpydoc's 8MHz wait-state injection interface and anything else I want to do with the IO ports.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #412 on: August 20, 2017, 08:46:34 pm »

Now If you can modify Cbios you could get CP/M3 running and have a larger space for programs.
You could also modify Cbios and get turbodos running. This is a networking system
Both CP/m3 & turbodos want more memory.

Yes, I'd like to upgrade to CP/M 3 but haven't even started looking at where to get it from, let alone its system requirements etc. yet. Still working on (and learning) the hardware currently.
Turbodos & CP/M3 and much more are on the web for down load

http://www.retrotechnology.com/dri/turbodos.html
http://www.mirrorservice.org/sites/www.bitsavers.org/pdf/ims/turboDos/
turboDos1.4_Z80impl_Jun84.pdf
turboDos1.4_Users_Guide_Jun84.pdf
Big thing for both is extra memory. With turbodos, If you link your two Z80's with SIO or other hardware You have two computers and both can access your CF card.
Scan read the Implementor's guide first.
CP/M3 is a harder read but works on same hardware less the network part.

Note that TurboDos can run CP/M programs and was used as a business networked computer system. 100's of Z80's in some systems in many buildings.

Quote
Yes, got that the I register holds the MSB for the vector table addresses.  So I could just copy the vector table to a place in RAM, say A000h, and modify the I register to hold A0h and hey presto! the vectors are moved into writable RAM?
YES
Or you could switch between two different tables.
Quote
Not so good for code commenting and readability though?
You can make data tables like this very easy to read. You do not have to put all values on one line, you can use many lines.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #413 on: August 20, 2017, 08:57:20 pm »
What Ram and eeprom are you using now?

For the ROM I'm using a 39SF010A and the RAM is an AS6C1008-55PCN.

128k ram will work for CP/M3 & Turbodos, More is better.
Simple is 74??273 and some data mux chips.

While I am thinking of it
The Z80 has limited pin drive capability, Might want to keep an eye on this.
 
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #414 on: August 22, 2017, 10:00:44 am »
While I am thinking of it
The Z80 has limited pin drive capability, Might want to keep an eye on this.

Well I'm hoping that eventually, if I ever get this off breadboard and onto a proper PCB, I'll be adding bus drivers/buffers to ease the load from the Z80.  Other than a PIO and keyboard/display modules though, the only other major additions I'd be looking to add would be an SPI/I2C bus (likely via the PIO). 

It seems most of the components I've got, like the CTC and PIO, are all 4MHz components so the clock speed is going to be staying at 3.68MHz for the foreseeable until I can replace the CTC and PIO with 8MHz parts.  As it's not essential, it's not a priority though.

I'm itching to get the PSG up and running, but it's going to involve a lot of effort on the software side, so I've been thinking about getting the Z80 access to the remainder of the 128K SRAM before I start writing the PSG software, as it might mean I have to go back and re-write routines if I do it the other way around.

So, I want to get my head around memory paging now.  Let me see if I understand the principle - the upper 64K of the SRAM (or anything above 64K in an arbitrarily-sized RAM space) is effectively divided up into 16K (for example)  'pages' by the memory addressing hardware, able to be swapped into the Z80's addressable RAM space via clever memory address switching and IO calls?

The area that's switched in/out resides in the TPA somewhere for CP/M, leaving low and high RAM either side to retain things like the stack, CP/M, drivers and space for the program making use of the paged memory?

So how do we choose the memory addresses for the paged memory block? Does CP/M/TurboDOS have specific requirements? There must be a section of the OS that will need to be modified to my specific hardware to allow it to page the memory at a program or user request?

And most importantly - what is the simplest way to implement memory paging in (and with the minimum additional) hardware?  I'm not an electronics expert (or even experienced at it) and my requirements for the SBC are modest, so I don't need to be able to page 1MB of RAM or anything - I'd just like to implement it to use the full 128K SRAM that I've got already.  Seems I've got some research to do.  ;)
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #415 on: August 22, 2017, 01:37:47 pm »


Read the section in Turbodos.

You have a software driver to write for CP/M3 or TurboDos.

Os tells driver what it wants, driver switches hardware.

For memory, Easy way to think is Huge memory, 0-? meg ram
So you wire up memory to be huge with x number of address lines.
You do not have it now but think ahead as more address lines can be cheap and easy.
Easy way to think is all memory chips same size. You have 8 same size chips when using a 138.
If you do not have same size chips, then pretend it is same size to keep it simple

Take a look at different 512K 32-pin memory chips. There are different types, what pins are used for what?
Then look at what you have for chips.
At most a few jumpers lets all work in socket.

 
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #416 on: August 22, 2017, 08:19:41 pm »

Memory management

To keep is simple to do and simple for me to say, You have
0- 128K rom     
128-256k ram
This is Memory map for your memory chips

You are going to put a circuit before the address inputs of memory.

74xx273
https://assets.nexperia.com/documents/data-sheet/74HC_HCT273.pdf
Cold boot clears chip
Z80 Writes data to chip with OUT instruction.

74xx153
https://assets.nexperia.com/documents/data-sheet/74HC_HCT153.pdf
Inputs to chip are outputs of 74xx273
Outputs of chip are high address lines t0 memory.
Select inputs are Z80 A14 & A15

This two chip solution is just two output address lines and uses two z80 address lines. A gain of 0, Need a second copy of circuit
You now have two 74xx273 & 2 74xx153
This circuit is using the two Z80 address lines to select 4 address lines for output, A gain of two address lines for an address range of 0-256k.
 
At cold boot, 0-16k from rom shows four times in Z80 address space.
After the Z80 does two Output instructions, You can have any 16k block of memory showing in the four 16k blocks in Z80 address apace.

Grant's Rom/Ram circuit is not needed.
You need to add one more chip to handle the two output addresses. A 74xx138 will work and leave some select lines for more IO output.

74xx138
https://www.diodes.com/assets/Datasheets/74HC138.pdf
One low enable input is connected to existing 74xx138
Second low enable input is connected to Z80 WR

Now for CP/M3 and TurboDos, you will want to change the two center blocks most of the time. Suggest putting these 8-bits on same 74xx273.

If you want to cripple this design a little, the upper 16k bank will stay the same, so you could strap these inputs to 74xx153 & gain 4-bits for other use in one of the 74xx273

This will work with what you have.
It is possible to add another pair of 74xx273 & 74xx153 and gain 2 more address lines and expand the memory range to 0-1024k

DMA
Both CP/M3 & TurboDos talk about DMA moving areas of data. With No DMA device the Z80 does this.
If the area to be moved is inside the source bank & destation bank then one move will work. But you can not expect all programmers to make it this easy. Normally the OS will keep one end of move in same bank, but programmer controls other end. In this case DMA could be two smaller moves with a bank change between the moves.
I state this now so you know some care is needed when this is programmed.

When you go looking at changes & improvements to this, you need to ask "will it give an improvement?"
If you are using CP/M3 or TurboDos, can the improvement be used?

 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #417 on: August 22, 2017, 10:14:08 pm »
Thanks C - some awesome information there that I'll need to go away and digest. I'm a visual learner when it comes to this stuff, so expect me to come back in a few days with a schematic representation of how I've interpreted your instructions for feedback and corrections. ;)
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #418 on: August 22, 2017, 10:37:24 pm »
Never a great artist.

What I listed

That mess is a simple 4 pole 4 throw switch with the Z80 address lines controlling the switch.
The Switch is just selecting the outputs of latches that the Z80 can write to with an OUT instruction.

Two address lines in = 4 address lines out.


Out 0  sets four bit address of Z80 0-16k & four bit address of Z80 48-64k
Out 1 sets   four bit address of Z80 16-32K & four bit address of Z80 32-48k

Software should store a copy of what is written in common memory.


« Last Edit: August 23, 2017, 10:04:51 pm by C »
 

Offline grumpydoc

  • Super Contributor
  • ***
  • Posts: 2905
  • Country: gb
Re: Z80 Homebrew Computer - fault finding
« Reply #419 on: August 28, 2017, 05:50:57 pm »
As stated PIO is easy out but has problems, the part I do not like is the  bit banging in place of simple read or write..

I would think that most of the time a program would be writing to the 3-8912.

This lead to How fast can the Z80 write to the 3-8912. I see two Z80 IO writes as the fastest ( a set address & write data). With this in mind, The data pins on 3-8912 can take from the Z80 starting IO cycle until just before Z80 starts next IO cycle, spanning the Instruction fetch and refresh..
Does this give enough time for zero Z80 waits?

For read you could do a start read followed by get data as two Z80 instructions or a wait state read.
When I first saw your suggestion I admit that I thought it wasn't that great an idea.

Having thought about it further I can see it has some merit, especially as clock speeds increase making the CPU very much faster than the PSG - so you'd start to need a lot of wait states to get the interface to work..

Given that OUT (X), A is 11 t-states I get the argument that while the IO read or write might not allow enough time, being only 4 t-states, we would need a clock speed of 22MHz before the whole instruction would take less than 500ns. So, yes, if one could arrange that the write completes while the Z80 is doing the next instruction there should be enough time even if it is a further write (as you say the most common access pattern will be one write to latch the address and one to write into the PSG register).

Doing it this way would mean the Z80 was not held up by wait states - but, to be fair even if you add 7 you will not even double the time for the whole I/O cycle.

However that will be at the cost of a more complex hardware interface. I haven't really tried to come up with a schematic but I can't quite see that you can do it with two main chips plus a couple of gates as I proposed.

Read seems like it would be more complex than with my suggested interface as well.

Why not support your suggestion with the details of the hardware interface and the timing. It seems only fair as I put the effort in to do that :)

 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #420 on: August 29, 2017, 08:15:25 pm »
Firstly C, thanks very much for the schematic - makes it much easier for me to understand.  :-+

Unfortunately I haven't got the ICs to implement memory mapping at the moment and I've also gotten a little sidetracked with another task.  I've had a PIO sitting around doing nothing and as an I2C interface is on my wishlist, I've wired it into the SBC and hooked it up.  All good so far.

I've been following this guide - http://www.blunk-electronic.de/train-z/pdf/howto_program_the_Z80-SIO.pdf - page 28 outlines an I2C interface using the PIO, which goes on to include some simple assembly routines to cover the basics.  It doesn't quite go as far as setting up a working I2C interface in software, but it seems to be a good starting point.

I was just wondering if anyone had any thoughts on the PIO/I2C design in the document above?  Is it a good implementation or is there a simpler way I can do it?  I've looked into getting a proper parallel/I2C chip, like the PCF8584, but I'm limited (mostly by soldering skill) to DIP packages - I don't really want to touch SMT unless I absolutely have to.  So, as a result, these DIP chips are prohibitively expensive (and limited to eBay.)  One reason for going with the PIO setup was that I could use the second port to create an SPI interface (also on my wish list) maybe.
 

Offline C

  • Super Contributor
  • ***
  • Posts: 1346
  • Country: us
Re: Z80 Homebrew Computer - fault finding
« Reply #421 on: August 30, 2017, 09:13:31 pm »
Firstly C, thanks very much for the schematic - makes it much easier for me to understand.  :-+

Unfortunately I haven't got the ICs to implement memory mapping at the moment and I've also gotten a little sidetracked with another task. 

Think about memory mapping a moment.
The important thing is add little delay to a memory access as possible.. For My schematic that is switching time of the 74xx153. You loose this much time when accessing memory.
There are many ways to do this. Look at my schematic for ways you could modify it. What do you gain with the change, what do you loose?

Note that you could plan ahead to make adding memory management easy.
You could inset a memory breadboard between Z80 & memory.


I've had a PIO sitting around doing nothing and as an I2C interface is on my wishlist, I've wired it into the SBC and hooked it up.  All good so far.

I've been following this guide - http://www.blunk-electronic.de/train-z/pdf/howto_program_the_Z80-SIO.pdf - page 28 outlines an I2C interface using the PIO, which goes on to include some simple assembly routines to cover the basics.  It doesn't quite go as far as setting up a working I2C interface in software, but it seems to be a good starting point.

What are you wanting to build,
  A microcontroller or A microcomputer?

If you want to build a microcontroller, save a lot of time and money and start with a microcontroller.

If you want to build and learn about a microcomputer,
Get in the micorcomputer mind set, thinking the computer way of doing things.
First look at PIO
You have two signals that most microcontrollers do not have, ARDY & ASTB.
These two signals let bytes of data flow at rate both z80 & connected circuit can handle. Because you are handshaking at byte, you can send many bytes in a row with the same value. At the same time software load on Z80 is lower.
Signals like these are easy to get in hardware with a microcomputer.

Look at a chip that was built to make it simpler to do I/O
Intel 8212
http://blog.copcea.ro/files/datasheets/diverse/8212.pdf
The dashed box is around a 74xx273 & a 74xx244 logic equal. You have the clear input of the 273 and the tri-state output of 244.

Best idea is not to do I2C with out adding a proper I2C master like PCF8584.
To do I2C with anything less wastes more and more CPU time just to run the interface.

Then you talk about SPI, again best done in hardware. If the only thing SPI is a SD card used for storage then this might be worth the chips needed.

When you shift to bit-banning you loose a huge amount of speed and need a huge number of instructions on CPU to make up for missing hardware.

Keep in mind that you can only do a single thing at a time on an I2C or SPI bus.

So step one, cross off I2C & SPI from your lists of wants and instead list the function of the chip that you would attach.
Then think smart,
That PCF8584 costs about $4. It is cheaper to add an interface on Z80 that can talk to a microcontroller and let the microconrtroller then talk to I2C & SPI. This also lets Z80 do more with less software overhead.

If you are wanting to learn microcontroller stuff, use a microcontroller to start.

If you are wanting to learn microprocessors then look at areas that microprocessors are good at.

If you want something to interface, how about a  HD44780 LCD controller

Many used the HDLC mode of SIO to link systems. This gives you a packet like interface with 8-bit transparency for data and command/status. IBM called this SDLC and had huge networks.

Many used SCSI as a parallel interface between 8 systems. Not hard to do in hardware/software and supports  8-bit transparency.

If you want really extreme, Connect an ESP32 to your Z80.

Think about many CPU's. 
One TurboDos system I worked with had over 200 uses running CP/M programs. That is 200 Z80's for the users + more.
One 68K system with 8 users used a Z80 to do all IO.

The basics are
Memory management
Multi-port memory
Multi-processor shared bus
Processor with Many buses.
 
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #422 on: August 31, 2017, 11:15:12 am »
Think about memory mapping a moment.
The important thing is add little delay to a memory access as possible.. For My schematic that is switching time of the 74xx153. You loose this much time when accessing memory.
There are many ways to do this. Look at my schematic for ways you could modify it. What do you gain with the change, what do you loose?

Note that you could plan ahead to make adding memory management easy.

Yes, I'm going to need to put a little more time and thought into this modification.

Best idea is not to do I2C with out adding a proper I2C master like PCF8584.
To do I2C with anything less wastes more and more CPU time just to run the interface.

Then you talk about SPI, again best done in hardware. If the only thing SPI is a SD card used for storage then this might be worth the chips needed.

When you shift to bit-banning you loose a huge amount of speed and need a huge number of instructions on CPU to make up for missing hardware.

Ah okay, I'll have to consider getting some PCF8584s then.  Frankly the PIO method seemed a bit of a hack and I'm not having much luck getting it working currently, I was just put off by the prices of PCF8584s on eBay and the lack of availability of the DIP packages.  I'm waiting on some SOIC/DIP converters from China - when they arrive I'll take a closer look and see if I stand a chance of soldering an SMT version of the PCF8584 to one.

So step one, cross off I2C & SPI from your lists of wants and instead list the function of the chip that you would attach.
Then think smart,
That PCF8584 costs about $4. It is cheaper to add an interface on Z80 that can talk to a microcontroller and let the microconrtroller then talk to I2C & SPI. This also lets Z80 do more with less software overhead.

I've got an Arduino nano sitting around doing very little at the moment, I guess I could swap out the PIO and replace it with the nano, which would give me SPI and I2C in one hit.  It'd spur me on to learn more about microcontrollers, but it goes against the grain in terms of what I was originally trying to achieve with an 80's tech SBC, though there's been some feature creep with the addition of I2C and CompactFlash, admittedly.

Okay, a question about replacing the PIO with the nano (remember - I'm very inexperienced with electronics); the nano will take a non-trivial amount of time to service an IO request - it'll have to, for example, read the I2C bus and return data retrieved from the bus to the Z80's data bus.  What's the best way to tell the Z80 to wait?  Insert ~WAIT states?  Or am I getting way ahead of myself?

EDIT:

Okay, so some quick research indicates that I can't (or shouldn't) replace the PIO with the Nano, but use the PIO to interface the Nano to the Z80's bus and interrupt system?
« Last Edit: August 31, 2017, 12:47:59 pm by nockieboy »
 

Offline CJay

  • Super Contributor
  • ***
  • Posts: 4136
  • Country: gb
Re: Z80 Homebrew Computer - fault finding
« Reply #423 on: August 31, 2017, 12:58:34 pm »
Hold your fire on those PCF8584 chips in DIP, I may have some still sealed in bags from way back when...

I'll have a look later this evening if i remember.
 
The following users thanked this post: nockieboy

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: Z80 Homebrew Computer - fault finding
« Reply #424 on: August 31, 2017, 01:08:33 pm »
Hold your fire on those PCF8584 chips in DIP, I may have some still sealed in bags from way back when...

I'll have a look later this evening if i remember.

That'd be awesome if you can, CJay - and massively appreciated!  :-+
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf