My bad on the 168 - it looks like an 8 on the compressed image on the website but yes on the pdf it is a 165. I fixed it on my post above.
Good question! I think there are many solutions. One I'd like to test out (boards on the way) is to use a low value resistor. High enough that the propeller can force the pin to a certain state but low enough that it doesn't upset normal Z80 operation. I'm guessing something like about 220 ohms. So there is a 220 ohm resistor on the Z80 /WR and /RD pins and so the Z80 is trying to drive /RD low and /WR high but the propeller forces the voltage at the memory chip to /RD high and /WR low. The ram /OE should not matter as the ram needs to be enabled either way.
Untested as yet but I'm hopeful that two resistors will save using a chip.
/OE enables means the RAM will be writing to the data bus.
Good way to let the smoke out of the RAM chip!
/BUSREQ tristates all the Z80 bus pins so an external device can control the bus. No idea why he does that though. Slowing (diddling) the CLK signal only changes the timing, so that may be used to slow the Z80 so that the bootstrap program can be written to the ram chip.
/OE enables means the RAM will be writing to the data bus.
Good way to let the smoke out of the RAM chip!
/OE (Output Enable) on the ram chip is normally connected to the Z80 /RD signal so with resistors on the Z80 /RD and /WR pins it should be ok as long as the current drive rating of the Z80 pins are not exceeded.
Perhaps you mean the /CS since the /OE pin of the ram is normally connected to the /RD signal from the Z80. With only one ram chip the /CS can be tied low so the ram is always enabled.
Perhaps you mean the /CS since the /OE pin of the ram is normally connected to the /RD signal from the Z80. With only one ram chip the /CS can be tied low so the ram is always enabled.
- yes sorry I meant /CS
So the ram chip is enabled by the Z80 but the propeller takes control of both read and write.
/BUSREQ tristates all the Z80 bus pins so an external device can control the bus. No idea why he does that though. Slowing (diddling) the CLK signal only changes the timing, so that may be used to slow the Z80 so that the bootstrap program can be written to the ram chip.
Error on the schematic?
Or maybe he didn't want to leave it floating and really did tie it to /RESET?
I couldn't find any mention of /BUSREQ in the Z80CTRL.SPIN file...
But it does name P9 as Z80 /RESET.
And the '165 is there to read the IORQ port address.
He's using all 256 port addresses for CP/M service requests!
That's going to be slower than what I had in mind, but drops A0 (and saves that pin).
But if /BUSREQ is asserted there will be nothing on the port address lines to shift into the Prop???
I still don't see the CLK signal trick.
It is used as the Z80 CLK - AND - the clk signal to the shift register - at the same time.
It's a mystery!
[one[hopefully last] edit tonight?]
/BUSREQ would clear the data bus so that the Prop can write to RAM?
(kwinn got it)
When all else fails, read the source code!
' Z80 pin masks
c_CpuIoReqMsk = 1 << CPU_IOREQ_PIN ' Mask to read Z80 IO request line (/IOREQ)
c_CpuResetMsk = 1 << CPU_RESET_PIN ' Mask to set Z80 reset line (/RESET)
c_CpuClkMsk = 1 << CPU_CLK_PIN ' Mask to set Z80 clock line (CLK), also tied to LOAD/SHIFT pin on 74HC165
c_CpuRdMsk = 1 << CPU_RD_PIN ' Mask to read/set Z80 data read line (/RD)
c_CpuWtMsk = 1 << CPU_WT_PIN ' Mask to read/set Z80 data write line (/WT)
c_CpuEnMsk = 1 << CPU_EN_PIN ' Mask to set enable pin for RD/WT line buffer (74LV367)
c_CpuAdrDataMsk = 1 << CPU_ADRQ_PIN ' Mask to read port address value from parallel to serial IC (74HC165)
c_CpuAdrClkMsk = 1 << CPU_ADRCLK_PIN ' Mask to set port address clock on parallel to serial IC (74HC165)
And down in the DAT section...
Z80_BootNext waitpne CpuRdMsk, CpuRdMsk ' Wait for Z80 RD line to go low
mov FRQB, #0 ' Stop Z80 clock accumulation
' We have a read request, Z80 has a valid address and /MEMREQ signal.
' Z80 is in read mode so data lines are inputs.
' Save boot loader byte
rdbyte T1, T3 'read next boot loader byte
add T3, #1
'Place the data on the Z80/Ram data buss (P0..P7)
andn OUTA, #255
or OUTA, T1
or DIRA, #255 'Set data lines as outputs
'Data is output to ram, Z80 hold address and ram chip enable.
' nop 'wait for ram to ready
'activate write line on ram
andn OUTA, CpuWtMsk
' nop 'wait for ram to ready
'Disable ram write signal
or OUTA, CpuWtMsk
'Now feed the Z80 a NOP opcode ( nop = 0 )
andn OUTA, #255
'Run Z80 until RD line is high
mov FRQB, CpuClockFreq 'Run the Z80
waitpeq CpuRdMsk, CpuRdMsk 'Wait for RD line to go high
'Set the Data buss to inputs
andn DIRA, #255 'Set data lines as inputs
djnz T4, #Z80_BootNext
'Boot loader is copied to Z80 ram, rest CPU and we are ready to run
call #Z80_Reset
Z80_Boot_ret ret
The Z80 does not really have a /CS signal. In the early days the ram chips were pretty small so /CS was generated using some of the address msb's and /MREQ. Typically this was done with a '155, '138, or '139. It's been so long since I've done anything with the Z80 that I forgot about the /MREQ and /IORQ signals. You will need to use /MREQ for the ram /CS, and /IORQ for I/O port requests.
Or maybe he didn't want to leave it floating and really did tie it to /RESET?
I couldn't find any mention of /BUSREQ in the Z80CTRL.SPIN file...
But it does name P9 as Z80 /RESET.
I am leaning towards it being an error. It has been a long time since I did any prototyping with the Z80, but IIRC the /BUSREQ was normally pulled up to Vcc so that external hardware could take over the bus if needed, and it was high otherwise. One piece of test equipment I lugged around let me plug a couple of ribbon cables into the CPU board and examine all the eprom and ram, read the status of input ports, and write data to output ports by pulling the /BUSREQ low.
Error on the schematic?
.............................................................
/BUSREQ would clear the data bus so that the Prop can write to RAM?
(kwinn got it)
Missed this last bit earlier. No, you would not want to use /BUSREQ for writing to the ram. When it is pulled low the Z80 CPU sets its address, data, and control signals to the high-impedance state with the rising edge of the next clock pulse. That means the address bits are floating instead of providing a valid ram address for the prop to write to.
After looking at the schematic and the propeller software for the Mini80 I think it will take a bit of study to see what is actually done. There seem to be a few errors and omissions in the schematic. I think the minimal system Dr_Acula wants is possible, and the Mini80 is close, but it needs a bit of work to get there.
Tying /CK to the '165 serial in let's you get a ninth bit shifted in. If P10 is also connected there it is probably a mistake. The resolution of the schematic makes it very hard to read so it may be necessary to use the software to verify the pinouts.
Tying /CK to the '165 serial in let's you get a ninth bit shifted in. If P10 is also connected there it is probably a mistake. The resolution of the schematic makes it very hard to read so it may be necessary to use the software to verify the pinouts.
cavelamb, thanks for bringing that PDF to my attention. I tried downloading it before but all I got was some PCB pads scattered over the page. Switched from Firefox to Chrome and downloaded a good copy. Another puzzle to figure out!
After a careful look at the schematic I think it is possible to build the simple circuit Dr_Acula suggested as long as his idea of using resistors for the read and write signals works.
By removing the '165 and '367 from the circuit P13, P14, and P15 are freed up. That means the prop can no longer input A0 – A7 and the /M1 state from the Z80.
The /M1 signal is used to indicate an instruction fetch. Since the prop will be looking at the /RD signal and feeding NOP instructions to the Z80 while it loads the boot program I do not think it is needed. Every memory read will be an instruction fetch. If it turns out /M1 is needed then P13 can be used and the number of prop ports reduced to 2.
I would suggest using P13, P14, and P15 to read A5, A6, and A7 of the Z80 address bus to decode them as 4 I/O ports occupying the range of hex 80 to FF, leaving the 128 addresses from hex 00 to 7F for the Z80.
The rest of the pin assignments could stay pretty much as they are so:
I can't help thinking that one should use a couple of diodes and a resistor to combine the /RD, /WR signals from Z80 and Prop. Perhaps with pull ups if required.
This might not be as minimalist as having the devices fight over those signals through a resistor but it makes me feel better and at least is not another chip that needs two power lines and decoupling caps.
cavelamb, thanks for bringing that PDF to my attention. I tried downloading it before but all I got was some PCB pads scattered over the page. Switched from Firefox to Chrome and downloaded a good copy. Another puzzle to figure out!
After a careful look at the schematic I think it is possible to build the simple circuit Dr_Acula suggested as long as his idea of using resistors for the read and write signals works.
By removing the '165 and '367 from the circuit P13, P14, and P15 are freed up. That means the prop can no longer input A0 – A7 and the /M1 state from the Z80.
The /M1 signal is used to indicate an instruction fetch. Since the prop will be looking at the /RD signal and feeding NOP instructions to the Z80 while it loads the boot program I do not think it is needed. Every memory read will be an instruction fetch. If it turns out /M1 is needed then P13 can be used and the number of prop ports reduced to 2.
I would suggest using P13, P14, and P15 to read A5, A6, and A7 of the Z80 address bus to decode them as 4 I/O ports occupying the range of hex 80 to FF, leaving the 128 addresses from hex 00 to 7F for the Z80.
The rest of the pin assignments could stay pretty much as they are so:
/IORQ and /M1 together indicate an interrupt response.
I thought That might be why the 9th bit was tied to /M1.
It would be a way to differentiate between an Input/output
cycle or an interrupt cycle.
But it looks like interrupts are NOT use. (?)
At least as far as I can read PASM...
But that would be why the 9th bit is be fed to the '165.
No, all the code does is read 8 bits (??) as the IORQ port address.
For I/O operations the Z80 puts the desired port address on the low 8 address lines.
It looks like this mechanism is how the PROP reads the desired port address from the Z80
without having to dedicate 8 Prop pins to the low 8 address lines.
kwinn:
Decoding 128 port address space only takes one address line.
(well, as long as we are only using the traditional 256 port address system )
I've been saying A0, but you are right; A7 would be a better choice.
A0 would divide the IO space into even and odd -adequate for a minimal system,
but would not preserve any IO space for the Z80 to use for anything else.
A7 would divide IO space into upper and lower 128 ports, and I now realize that
as long as the Prop will decode those internally (via software no less!) then the
rest are still safe for the Z80 to use itslef. All that would take is a minor modificatin
to the Mini-80 driver to allow the IORQ cycle to run unhindered (for those addresses).
And no external decoder would be needed.
But it IS necessary for the Prop to be able to read those low 8 address lines -
somehow -
to know what port is being addressed.
Keep the '165.
As for "feeding No-Ops", the Minio-80 doesn't do that.
It simply stops the Z80 clock.
It uses counter A in NCO mode to do that.
Slick and simple at the same time.
Elegant...
For instance:
Z80_Reset mov CTRB, #0 ' Disable counter B, no output on CPU_CLK_PIN
mov PHSB, #0
mov FRQB, #0 ' Stop clock accumulation
mov CTRB, #0 ' Disable counter A, no output on CPU_ADRCLK_PIN
' Z80 clock is stopped, setup base pin directions
mov OUTA, #0
mov DIRA, BaseDirRegMsk
' CPU reset is active, clock is low, and the RD/WT line buffer is enabled.
' Run the clock for at least 8 to 10 CPU clock cycles before RESET is disabled
mov T1, #10
mov T2, CNT
add T2, #32
'Set Z80 clock line high
' or DIRA, CpuClkMsk
Z80_ResetLoop or OUTA, CpuClkMsk
waitcnt T2, #32
'Set Z80 clock line low
andn OUTA, CpuClkMsk
waitcnt T2, #32
'See if we need more clock pulses
djnz T1, #Z80_ResetLoop
'Release rest line, there is a 10k pullup on reset so just disable as output
or OUTA, CpuResetMsk
andn DIRA, CpuResetMsk
'Z80 has been reset, ready clock but do not start, then return
mov CTRB, CpuClockMode ' Set counter B to NCO mode, output on CPU_CLK_PIN
mov FRQA, #0
mov PHSA, #0
mov CTRA, AdrClockMode ' Set counter A to NCO mode, output on CPU_ADRCLK_PIN
Z80_Reset_ret ret
Guys, the hardware for this project is fairly trivial.
The software is not!
In my feeble mind I had something about ROMless booting, I thought that it was the NOP stuffings - but now I wonder if it was something like this that was niggling at me (fogged by the apple juice).
I was re-reading the Zilog Z80 User's Manual when I stumbled across this:
When the clock input to the CMOS Z80 CPU is stopped at either a High or
Low level, the CMOS Z80 CPU stops its operation and maintains all
registers and control signals. However, ICC2 (standby supply current) is
guaranteed only when the system clock is stopped at a Low level during T4
of the machine cycle following the execution of the HALT instruction.
And then:
The system clock must be supplied to the CMOS Z80 CPU to release the
power-down state. When the system clock is supplied to the CLK input, the
CMOS Z80 CPU restarts operations from the point at which the powerdown
state was implemented. The timing diagrams for the release from
power-down mode are featured in Figure 13 , 14 and 15.
When the HALT instruction is executed to enter the power-down state, the
CMOS Z80 CPU also enters the HALT state. An interrupt signal (either
NMI or ANT) or a RESET signal must be applied to the CPU after the
system clock is supplied in order to release the power-down state.
Obviously the Mini80 works but I cannot see any code that allows for this. Or is there?
EDIT: I see it now at the bottom of the code in post #50
As for "feeding No-Ops", the Minio-80 doesn't do that.
It simply stops the Z80 clock.
That can't be right. The mini80 page clearly describes the boot sequence:
1. Pull Z80 reset line low.
2. Generate enough clock pulse to allow Z80 core to fully reset then set
reset line high.
3. Set the tri-state buffer enable pin high to tri-state Z80 read and
write lines (/RD, /WT).
4. Provide clock pulses to the Z80 until the Z80 indicates a read operation.
5. Place the desire data on to the data buss, then pulse the RAM /WT pin low to write the memory location, Z80 provides address and RAM chip select.
6. Place the 8 bit Z80 op-code NOP (0) on the data buss.
7. Provide clock pulses to the Z80 until the Z80 indicates the read operation
completed (/RD = high).
8. Repeat steps 4..7 until the required boot code is copied to RAM, each
cycle the Z80 will increment its memory address starting at address zero.
9. Pull Z80 reset line low.
10. Generate enough clock pulse to allow Z80 core to fully reset then set
reset line high.
11. Set the tri-state buffer enable pin low to enable Z80 read and write
lines (/RD, /WT).
12. Set the Propeller chip counter to clock the CPU at required frequency.
Given that the address bus is not connected to the Prop the Z80 has to provide all the addresses required to write the boot code. In order to step sequentially through those addresses it has to being seing a NOP from each location.
Step 5 writes the data to RAM and step 6 puts a NOP on the data bus for the Z80 to read thus advancing it to the next address.
Or are you saying the mini80 Prop code does not do that?
I can't help thinking that one should use a couple of diodes and a resistor to combine the /RD, /WR signals from Z80 and Prop. Perhaps with pull ups if required.
This might not be as minimalist as having the devices fight over those signals through a resistor but it makes me feel better and at least is not another chip that needs two power lines and decoupling caps.
That would need 4 diodes, 2 pullup resistors, and 2 current limiting resistors to avoid any possible problems. Two series resistors do the same thing.
/IORQ and /M1 together indicate an interrupt response.
I thought That might be why the 9th bit was tied to /M1.
It would be a way to differentiate between an Input/output
cycle or an interrupt cycle.
But it looks like interrupts are NOT use. (?)
At least as far as I can read PASM...
But that would be why the 9th bit is be fed to the '165.
No, all the code does is read 8 bits (??) as the IORQ port address.
The '165 loads A0 to A7 (the I/O port address for I/O operations) in and and then shifts it in to the prop. As each bit is shifted out of the '165 the state of /M1 is shifted in, until all 8 bits of the '165 contain the state of the M1 pin. The next shift will then shift the M1 state in to the Prop.
Quote from the Z80 manual on /M1 “M1 - Machine Cycle One (output, active Low). M1, together with MREQ, indicates that the current machine cycle is the opcode fetch cycle of an instruction execution. M1 together with IORQ, indicates an interrupt acknowledge cycle.
For I/O operations the Z80 puts the desired port address on the low 8 address lines.
It looks like this mechanism is how the PROP reads the desired port address from the Z80
without having to dedicate 8 Prop pins to the low 8 address lines.
Exactly.
kwinn:
Decoding 128 port address space only takes one address line.
(well, as long as we are only using the traditional 256 port address system )
I've been saying A0, but you are right; A7 would be a better choice.
A0 would divide the IO space into even and odd -adequate for a minimal system,
but would not preserve any IO space for the Z80 to use for anything else.
A7 would divide IO space into upper and lower 128 ports, and I now realize that
as long as the Prop will decode those internally (via software no less!) then the
rest are still safe for the Z80 to use itslef. All that would take is a minor modificatin
to the Mini-80 driver to allow the IORQ cycle to run unhindered (for those addresses).
And no external decoder would be needed.
Correct again. A7 high (along with /IORQ) indicates that this is an address for I/O hardware attached to the Prop. The other two bits I suggested be used allow us to select one of four I/O devices. That would allow us to choose between the SD card, serial connection (Prop plug), and two other devices.
But it IS necessary for the Prop to be able to read those low 8 address lines -
somehow -
to know what port is being addressed.
Keep the '165.
Not necessarily. If you can not add more I/O hardware to the Prop you do not need more than four port addresses. Yes, it wastes a lot of potential I/O ports (only 4 of 128 possible ports used), but that simplifies the hardware and still leaves the Z80 with a possible 128 more ports.
As for "feeding No-Ops", the Mini-80 doesn't do that.
It simply stops the Z80 clock.
It uses counter A in NCO mode to do that.
Slick and simple at the same time.
Elegant...
Yes, it is quite elegant, and it does feed no-op's to the Z80 in order to have it generate sequential addresses for writing the bootstrap program into the ram. I have not had time to analyze and comment the code but the basic sequence is as described in the Min80 Docs
1. Pull Z80 reset line low.
2. Generate enough clock pulse to allow Z80 core to fully reset then set reset line high.
3. Set the tri-state buffer enable pin high to tri-state Z80 read and write lines (/RD, /WT).
4. Provide clock pulses to the Z80 until the Z80 indicates a read operation.
5. Place the desire data on to the data buss, then pulse the RAM /WT pin low to write the memory location, Z80 provides address and RAM chip select.
6. Place the 8 bit Z80 op-code NOP (0) on the data buss.
7. Provide clock pulses to the Z80 until the Z80 indicates the read operation completed (/RD = high).
8. Repeat steps 4..7 until the required boot code is copied to RAM, each cycle the Z80 will increment its memory*address starting at address zero.
9. Pull Z80 reset line low.
10. Generate enough clock pulse to allow Z80 core to fully reset then set reset line high.
11. Set the tri-state buffer enable pin*low to*enable Z80 read and write lines (/RD, /WT).
12. Set the Propeller chip counter to clock the CPU at required frequency.
At this point the boot loader*has completed and the Z80 will begin to execute the code loaded in to*the RAM memory starting at memory address zero.
Line 5 writes the data from the prop to the ram. Line 6 then puts the NOP instruction on the data bus and feeds it to the Z80.
Guys, the hardware for this project is fairly trivial.
The software is not!
Very true, but the software is already written. While modifying it is not trivial, the changes needed to accommodate removing the '165 and '367 are not that great.
Just wanted to say thanks for pointing out the mistake I made on the Mini80 project schematic.
The P9 line is used to control the Z80 /RESET pin and should not be connected to the /BUSREQ pin. I do not use the /BUSREQ signal other then to pull it to a high level using a 10k resistor to disable it. I have updated the WEB site to reflect the changes.
It has been interesting to follow the forum posts, I went thru many of the same design considerations when I developed the Mini80.
FYI:
The M1 signal is not currently used and does not need to be connected to the 165 shift register. I may use it in the future to decode IRQ vector requests from the Z80.
The P10 line has dual uses; primaraly it is used to clock the Z80, P10 is also used to control the Z80 I/O address loading for the 74hc165. P10 must be in the low state to load the Z80 address, then changed to the high state to shift out the address to the Prop chip.
Some of this code is not needed - even the debugging back to the propeller terminal (F12) is not needed as this is debugging with a logic probe, one instruction at a time. So it will work without the .sio and .str objects
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
_baudRateSpeed = 115200 ' Teraterm does not work at this speed. Use hyperterminal or proptool terminal
_receiverPin = 31
_transmitterPin = 30
OBJ
delay: "Timing" ' for millisecond delays
sio : "pcFullDuplexSerial2FC" ' serial port
str : "ASCII0_STREngine" ' strings
VAR
PUB Main
sio.AddPort(0, _receiverPin, _transmitterPin, -1, -1, 0, 0, _baudRateSpeed)
sio.start
Z80Boot
'repeat
' PrintString(string("Test"))
repeat ' endless loop
PUB Z80Boot | i
' P0-7 is Z80 data bus 0-7
' P8 = Z80 /IORQ
' P9 = Z80 /WR
' P10 = Z80 /RD
' P11 = Z80 Clk
' P12 = Z80 A0
' P13 = Z80 /RESET
Z80ResetLow ' set reset low
Z80Clock(5) ' clock several times to register the reset
Z80ResetHigh ' set reset high
Z80WaitForRdLow ' clock until rd goes low, at this point address should be 00000000_00000000
repeat i from 0 to 2
Z80WriteByteToRam(byte[@Z80BootProgram][i]) ' move a byte into ram
Z80DataBusNOP ' sets data bus to zero, Z80 reads this as a NOP and proceeds to next instruciton
Z80Clock(2) ' two clocks
Z80WaitForRdLow ' wait until reads next value
Z80ResetLow ' reset the Z80 ready to run the program
Z80Clock(5) ' wait till responds
Z80ResetHigh ' reset high
Z80Clock(12) 'run the little program, test pin status with different number of clock pulses
repeat ' do nothing
DAT
Z80BootProgram
byte $3E,$41,$76 '
' ld a,65
' halt
' end ' write this in the N8VEM program, compile, read with hexedit
PUB Z80Clock(n)
DIRA |= %00000000_00000000_00001000_00000000 ' enable the clock pin as an output\
repeat n
OUTA |= %00000000_00000000_00001000_00000000 ' clock high
delay.pause1ms(10) ' delay if needed
OUTA &= %11111111_11111111_11110111_11111111 ' clock low
delay.pause1ms(10) ' delay
PUB Z80ResetLow
DIRA &= %11111111_11111111_11000000_00000000 ' data bus and /iorq /wr /rd clk A0 and /reset all HiZ (pulled high with 10k)
DIRA |= %00000000_00000000_00100000_00000000 ' reset pin = output
OUTA &= %11111111_11111111_11011111_11111111 ' set reset pin low
PUB Z80ResetHigh
DIRA |= %00000000_00000000_00100000_00000000 ' reset pin = output
OUTA |= %00000000_00000000_00100000_00000000 ' set reset pin high
PUB Z80WaitForRdLow ' keep clocking until the /rd pin goes low
repeat while (INA & %00000000_00000000_00000100_00000000)
Z80Clock(1)
PUB Z80WriteByteToRam(n)
n &= %00000000_00000000_00000000_11111111 ' mask off all but lower 8 bits
DIRA |= %00000000_00000000_00000110_11111111 ' set P0-P7 as outputs and also /RD and /WR as outputs
OUTA &= %11111111_11111111_11111111_00000000 ' mask outa lower 8 bits to zero
OUTA |= n ' combine with the data byte
OUTA &= %11111111_11111111_11111101_11111111 ' force /WR low
OUTA |= %00000000_00000000_00000100_00000000 ' force /RD high
delay.pause1ms(10) ' delay, make as short as possible
OUTA |= %00000000_00000000_00000010_00000000 ' write high
DIRA &= %11111111_11111111_11111001_00000000 'set /rd /wr and the data bits to inputs (highZ)
PUB Z80DataBusNOP ' put zero (NOP) on data bus
DIRA |= %00000000_00000000_00000000_11111111 ' set data bus to outputs
OUTA &= %11111111_11111111_11111111_00000000 ' set data bus to zero
PUB PrintStringCR(pstring)' sends pstring to the vga and serial port
PrintString(pstring) ' print the string
crlf
PUB PrintString(pstring)' sends pstring to the serial port with no CRLF
sio.str(0,pstring) ' send to com port
PUB PrintChar(c) ' sends c to vga and serial port
sio.tx(0,c) ' send to com port
PUB CRLF
PrintChar(13) ' send to vga
PrintChar(10) ' send to vga
PUB PrintDecimal(number) ' print the decimal value, useful for debuggin
PrintString(str.integerToDecimal(number, 10))
Attached photo of the board and schematic.
For the schematic (and as shown in the photo), lots of things can be omitted. The 5V regulator is not needed. Leave out the VGA display, audio, keyboard, TV and SD card. Leave out the MCP23008 (used for selecting memory banks). You could even leave out the propeller eeprom and test with just F10 if you want.
So chips are a Z80 and a memory chip, regulator and a download circuit. The pullups are important.
No problems it seems with the Z80 running at 3V3. It runs cold.
The clever bit is the two 220 ohm resistors which enable the propeller to force memory /rd and /wr pins into different states without upsetting the Z80.
So - this loads a tiny 3 byte program into the Z80, and then steps through and runs it.
I have tested each step with a logic probe and it seems to work just fine.
Program is all in spin at the moment and there are lots of delays. Things like the clock can be moved into pasm later.
This circuit is simple enough to be breadboarded. It uses even less components if you have a propplug.
With six Z80 pins under propeller control (reset, rd, wr, iorq, A0, clock) that should be enough for a fast comms protocol.
And great to see Shael here - so many brilliant ideas in that Mini80 board!
Just wanted to say thanks for pointing out the mistake I made on the Mini80 project schematic.
The P9 line is used to control the Z80 /RESET pin and should not be connected to the /BUSREQ pin. I do not use the /BUSREQ signal other then to pull it to a high level using a 10k resistor to disable it. I have updated the WEB site to reflect the changes.
It has been interesting to follow the forum posts, I went thru many of the same design considerations when I developed the Mini80.
FYI:
The M1 signal is not currently used and does not need to be connected to the 165 shift register. I may use it in the future to decode IRQ vector requests from the Z80.
The P10 line has dual uses; primaraly it is used to clock the Z80, P10 is also used to control the Z80 I/O address loading for the 74hc165. P10 must be in the low state to load the Z80 address, then changed to the high state to shift out the address to the Prop chip.
Shael!
Hey, nice to see you here.
And thank you so much for sharing your work.
Awesome stuff!
Comments
/OE enables means the RAM will be writing to the data bus.
Good way to let the smoke out of the RAM chip!
/OE (Output Enable) on the ram chip is normally connected to the Z80 /RD signal so with resistors on the Z80 /RD and /WR pins it should be ok as long as the current drive rating of the Z80 pins are not exceeded.
Perhaps you mean the /CS since the /OE pin of the ram is normally connected to the /RD signal from the Z80. With only one ram chip the /CS can be tied low so the ram is always enabled.
So the ram chip is enabled by the Z80 but the propeller takes control of both read and write.
Error on the schematic?
Or maybe he didn't want to leave it floating and really did tie it to /RESET?
I couldn't find any mention of /BUSREQ in the Z80CTRL.SPIN file...
But it does name P9 as Z80 /RESET.
And the '165 is there to read the IORQ port address.
He's using all 256 port addresses for CP/M service requests!
That's going to be slower than what I had in mind, but drops A0 (and saves that pin).
But if /BUSREQ is asserted there will be nothing on the port address lines to shift into the Prop???
I still don't see the CLK signal trick.
It is used as the Z80 CLK - AND - the clk signal to the shift register - at the same time.
It's a mystery!
[one[hopefully last] edit tonight?]
/BUSREQ would clear the data bus so that the Prop can write to RAM?
(kwinn got it)
When all else fails, read the source code!
I am leaning towards it being an error. It has been a long time since I did any prototyping with the Z80, but IIRC the /BUSREQ was normally pulled up to Vcc so that external hardware could take over the bus if needed, and it was high otherwise. One piece of test equipment I lugged around let me plug a couple of ribbon cables into the CPU board and examine all the eprom and ram, read the status of input ports, and write data to output ports by pulling the /BUSREQ low.
Enjoy!
Mike
Missed this last bit earlier. No, you would not want to use /BUSREQ for writing to the ram. When it is pulled low the Z80 CPU sets its address, data, and control signals to the high-impedance state with the rising edge of the next clock pulse. That means the address bits are floating instead of providing a valid ram address for the prop to write to.
After looking at the schematic and the propeller software for the Mini80 I think it will take a bit of study to see what is actually done. There seem to be a few errors and omissions in the schematic. I think the minimal system Dr_Acula wants is possible, and the Mini80 is close, but it needs a bit of work to get there.
Re the '165 I am not sure either why P10 is tied to both the /CK of the Z80 and the Serial In of the '165. From the '165 datasheet
Tying /CK to the '165 serial in let's you get a ninth bit shifted in. If P10 is also connected there it is probably a mistake. The resolution of the schematic makes it very hard to read so it may be necessary to use the software to verify the pinouts.
kwinn, there is a PDF version of the schematic hidden there.
http://www.shaels.net/index.php/mini80/mini80-general/119-mini8o-overview
Click on the pic of the schematic and it will offer it up.
All the source code is in the zip file at
http://www.shaels.net/index.php/mini80/downloads/121-mini80-prototype-project-files-2013-03-23
After a careful look at the schematic I think it is possible to build the simple circuit Dr_Acula suggested as long as his idea of using resistors for the read and write signals works.
By removing the '165 and '367 from the circuit P13, P14, and P15 are freed up. That means the prop can no longer input A0 – A7 and the /M1 state from the Z80.
The /M1 signal is used to indicate an instruction fetch. Since the prop will be looking at the /RD signal and feeding NOP instructions to the Z80 while it loads the boot program I do not think it is needed. Every memory read will be an instruction fetch. If it turns out /M1 is needed then P13 can be used and the number of prop ports reduced to 2.
I would suggest using P13, P14, and P15 to read A5, A6, and A7 of the Z80 address bus to decode them as 4 I/O ports occupying the range of hex 80 to FF, leaving the 128 addresses from hex 00 to 7F for the Z80.
The rest of the pin assignments could stay pretty much as they are so:
P0 - P7 D0 – D7 of the Z80 and ram chip.
P8 – Z80 /IORQ
P9 – Z80 /RESET
P10 – Z80 CLOCK
P11 – Z80 /RD, RAM /OE
P12 – Z80 /WR, RAM /WE
Good old fashioned "diode logic": http://en.wikipedia.org/wiki/Diode_logic
This might not be as minimalist as having the devices fight over those signals through a resistor but it makes me feel better and at least is not another chip that needs two power lines and decoupling caps.
How about becoming "minimalist-ist" about the number of silicon junctions?
On such a competition, I wonder what the ratio of the Prop's transistor count to the Z80's?
/IORQ and /M1 together indicate an interrupt response.
I thought That might be why the 9th bit was tied to /M1.
It would be a way to differentiate between an Input/output
cycle or an interrupt cycle.
But it looks like interrupts are NOT use. (?)
At least as far as I can read PASM...
But that would be why the 9th bit is be fed to the '165.
No, all the code does is read 8 bits (??) as the IORQ port address.
For I/O operations the Z80 puts the desired port address on the low 8 address lines.
It looks like this mechanism is how the PROP reads the desired port address from the Z80
without having to dedicate 8 Prop pins to the low 8 address lines.
kwinn:
Decoding 128 port address space only takes one address line.
(well, as long as we are only using the traditional 256 port address system )
I've been saying A0, but you are right; A7 would be a better choice.
A0 would divide the IO space into even and odd -adequate for a minimal system,
but would not preserve any IO space for the Z80 to use for anything else.
A7 would divide IO space into upper and lower 128 ports, and I now realize that
as long as the Prop will decode those internally (via software no less!) then the
rest are still safe for the Z80 to use itslef. All that would take is a minor modificatin
to the Mini-80 driver to allow the IORQ cycle to run unhindered (for those addresses).
And no external decoder would be needed.
But it IS necessary for the Prop to be able to read those low 8 address lines -
somehow -
to know what port is being addressed.
Keep the '165.
As for "feeding No-Ops", the Minio-80 doesn't do that.
It simply stops the Z80 clock.
It uses counter A in NCO mode to do that.
Slick and simple at the same time.
Elegant...
For instance:
Guys, the hardware for this project is fairly trivial.
The software is not!
Sorry all.
I will try to not post technical stuff after midnight....
http://www.jdm.homepage.dk/z80boot.htm
Alan
And then:
Obviously the Mini80 works but I cannot see any code that allows for this. Or is there?
EDIT: I see it now at the bottom of the code in post #50
That can't be right. The mini80 page clearly describes the boot sequence:
1. Pull Z80 reset line low.
2. Generate enough clock pulse to allow Z80 core to fully reset then set
reset line high.
3. Set the tri-state buffer enable pin high to tri-state Z80 read and
write lines (/RD, /WT).
4. Provide clock pulses to the Z80 until the Z80 indicates a read operation.
5. Place the desire data on to the data buss, then pulse the RAM /WT pin low to write the memory location, Z80 provides address and RAM chip select.
6. Place the 8 bit Z80 op-code NOP (0) on the data buss.
7. Provide clock pulses to the Z80 until the Z80 indicates the read operation
completed (/RD = high).
8. Repeat steps 4..7 until the required boot code is copied to RAM, each
cycle the Z80 will increment its memory address starting at address zero.
9. Pull Z80 reset line low.
10. Generate enough clock pulse to allow Z80 core to fully reset then set
reset line high.
11. Set the tri-state buffer enable pin low to enable Z80 read and write
lines (/RD, /WT).
12. Set the Propeller chip counter to clock the CPU at required frequency.
Given that the address bus is not connected to the Prop the Z80 has to provide all the addresses required to write the boot code. In order to step sequentially through those addresses it has to being seing a NOP from each location.
Step 5 writes the data to RAM and step 6 puts a NOP on the data bus for the Z80 to read thus advancing it to the next address.
Or are you saying the mini80 Prop code does not do that?
That would need 4 diodes, 2 pullup resistors, and 2 current limiting resistors to avoid any possible problems. Two series resistors do the same thing.
The '165 loads A0 to A7 (the I/O port address for I/O operations) in and and then shifts it in to the prop. As each bit is shifted out of the '165 the state of /M1 is shifted in, until all 8 bits of the '165 contain the state of the M1 pin. The next shift will then shift the M1 state in to the Prop.
Quote from the Z80 manual on /M1 “M1 - Machine Cycle One (output, active Low). M1, together with MREQ, indicates that the current machine cycle is the opcode fetch cycle of an instruction execution. M1 together with IORQ, indicates an interrupt acknowledge cycle.
Exactly.
Correct again. A7 high (along with /IORQ) indicates that this is an address for I/O hardware attached to the Prop. The other two bits I suggested be used allow us to select one of four I/O devices. That would allow us to choose between the SD card, serial connection (Prop plug), and two other devices.
Not necessarily. If you can not add more I/O hardware to the Prop you do not need more than four port addresses. Yes, it wastes a lot of potential I/O ports (only 4 of 128 possible ports used), but that simplifies the hardware and still leaves the Z80 with a possible 128 more ports.
Yes, it is quite elegant, and it does feed no-op's to the Z80 in order to have it generate sequential addresses for writing the bootstrap program into the ram. I have not had time to analyze and comment the code but the basic sequence is as described in the Min80 Docs
1. Pull Z80 reset line low.
2. Generate enough clock pulse to allow Z80 core to fully reset then set reset line high.
3. Set the tri-state buffer enable pin high to tri-state Z80 read and write lines (/RD, /WT).
4. Provide clock pulses to the Z80 until the Z80 indicates a read operation.
5. Place the desire data on to the data buss, then pulse the RAM /WT pin low to write the memory location, Z80 provides address and RAM chip select.
6. Place the 8 bit Z80 op-code NOP (0) on the data buss.
7. Provide clock pulses to the Z80 until the Z80 indicates the read operation completed (/RD = high).
8. Repeat steps 4..7 until the required boot code is copied to RAM, each cycle the Z80 will increment its memory*address starting at address zero.
9. Pull Z80 reset line low.
10. Generate enough clock pulse to allow Z80 core to fully reset then set reset line high.
11. Set the tri-state buffer enable pin*low to*enable Z80 read and write lines (/RD, /WT).
12. Set the Propeller chip counter to clock the CPU at required frequency.
At this point the boot loader*has completed and the Z80 will begin to execute the code loaded in to*the RAM memory starting at memory address zero.
Line 5 writes the data from the prop to the ram. Line 6 then puts the NOP instruction on the data bus and feeds it to the Z80.
Very true, but the software is already written. While modifying it is not trivial, the changes needed to accommodate removing the '165 and '367 are not that great.
The P9 line is used to control the Z80 /RESET pin and should not be connected to the /BUSREQ pin. I do not use the /BUSREQ signal other then to pull it to a high level using a 10k resistor to disable it. I have updated the WEB site to reflect the changes.
It has been interesting to follow the forum posts, I went thru many of the same design considerations when I developed the Mini80.
FYI:
The M1 signal is not currently used and does not need to be connected to the 165 shift register. I may use it in the future to decode IRQ vector requests from the Z80.
The P10 line has dual uses; primaraly it is used to clock the Z80, P10 is also used to control the Z80 I/O address loading for the 74hc165. P10 must be in the low state to load the Z80 address, then changed to the high state to shift out the address to the Prop chip.
Unfortunately I run Firefox, and so the .pdf version is just a bunch of pads and circles :-(
ADDIT I have downloaded the .pdf and opened it with Reader and that is all OK (even if the latest version of reader seems painfully slow)
Some of this code is not needed - even the debugging back to the propeller terminal (F12) is not needed as this is debugging with a logic probe, one instruction at a time. So it will work without the .sio and .str objects
Attached photo of the board and schematic.
For the schematic (and as shown in the photo), lots of things can be omitted. The 5V regulator is not needed. Leave out the VGA display, audio, keyboard, TV and SD card. Leave out the MCP23008 (used for selecting memory banks). You could even leave out the propeller eeprom and test with just F10 if you want.
So chips are a Z80 and a memory chip, regulator and a download circuit. The pullups are important.
No problems it seems with the Z80 running at 3V3. It runs cold.
The clever bit is the two 220 ohm resistors which enable the propeller to force memory /rd and /wr pins into different states without upsetting the Z80.
So - this loads a tiny 3 byte program into the Z80, and then steps through and runs it.
I have tested each step with a logic probe and it seems to work just fine.
Program is all in spin at the moment and there are lots of delays. Things like the clock can be moved into pasm later.
This circuit is simple enough to be breadboarded. It uses even less components if you have a propplug.
With six Z80 pins under propeller control (reset, rd, wr, iorq, A0, clock) that should be enough for a fast comms protocol.
And great to see Shael here - so many brilliant ideas in that Mini80 board!
Shael!
Hey, nice to see you here.
And thank you so much for sharing your work.
Awesome stuff!