 My nice new brother WP1 word processor. I could connect the Raspberry Pi up to the UART. Sadly this turns out not to be viable. This is a very cheap Psoc 5 development board. I need to go and pull up the Cyprus development kit and wire that up. Two macro cells and one unique PETA, whatever they are. This is recording what all the IO read accesses are. We're going to write this in Verilog and now we head over to the board. Returning 5A which is the right value. Okay so here is our Verilog and here is the value that we're returning. This is a hard coded value. In fact 5A is always being asserted to data W. It's only ever been output to the bus when OE is asserted which only ever happens when the CPU is reading from our IO port. We actually want real data to be read and written. So we need to get some of that from somewhere. And we're going to do it using status and control registers. So we've seen a status register before. This is a readable thing by the CPU. So we're going to have four of these. There are going to be four registers in our device that can be written to by the brother word processor. Why four? Because we can do four. And we need more than one because for something like a UART that I'm thinking of we have to have a read register, a write register. This is data in and out. And also a register used to tell the brother word processor when data is available and when it's safe to write a byte. So we're going to have to have at least two and so we might as well go the whole hog with four. So status registers allow the CPU in the PSOCK board to read stuff. Let's play as bus. Control registers allow it to write stuff. These can be set by software. Try to get these. Oh, they're not quite the same size, which is why they don't line up properly. The value of these can be set in software from the PSOCK processor. And it will then remember that value and continue to assert it to the output. So let's just set the names properly. Now it's important to note that inputs and outputs can do completely different things. When the brother word processor does a read, it doesn't have to read from... It'll always read from one of these control registers. This control register does not have to reflect the value of the status register. They are completely independent. So our UART data input and output registers are both going to be at index zero. So this is the one that's going to be read from by the brother word processor to indicate that it wants to get a byte. This is the one that's going to be written to by the brother word processor to indicate that it wants to send a byte. Now we need to send these into our bus interface. So we need to edit the symbol. So we need to make the box bigger first. And let's add digital input. So these are values provided to the bus interface by the PSOCK board CPU. We want digital outputs, put nought, I need to make the whole box bigger. I mentioned that this is a drawing package. It's not a very good drawing package. And you can actually move the position of the text independently of the pins. No one would do that. So let's move these a little bit closer to the output nodes. Okay, so duplicate. Okay, let's make this the right size. That's just the text. I want to edit the box as well. Add will do. Save, regenerate the verilog. Yes, it's safe to overwrite because it will preserve the stuff you edited. You can see it's now added the our additional inputs and outputs then over to the schematic. So we now want to wire these up like this. You can do all of this stuff from verilog and you can do all the verilog stuff using the schematic. I just think that some things are clearer with the schematic and some things are clearer with verilog. I'm not actually very good at verilog. So anyone who actually does it for a living is probably going to watch this and screen that I'm doing it all wrong. Okay, and we also need some clocks. It would be nice if there was a quick way to get at the standard system clock. Like so. Okay, does it build? It does not because I moved stuff around without changing the wiring. This is a bit of a problem with the system. It would be nice if it would rubber band the wiring for you which it does do sometimes but it's not consistent. Let me just... Where is that dot appearing? There we go. Okay, so let's build. It'll probably complain there's nothing writing to these. Yep. Okay, so we are now going to use a new verilog feature. If I can figure out... No, it's not that one. If I can figure out where it is. We need to tell the system that these parameters are registered. This means that they will remember their value. So we write a value to the output and it will keep asserting that value until we write it again. I'll now do it in code which is to add reg here. But of course, the next time we update the verilog it will lose this. I think we can... Yeah, let's just do it like that. It's simplest. I don't think we need to update the verilog again. Net 2347 is floating which is 2347. 232, 233, 234. I did set output to to be registered. This is no longer floating. It seems to be only 233 and 234. Do I get an error for 235? No. 234, 76543210, 233, 765234, 233. That's weird. Why is it doing that? If all else fails to a clean and rebuild it's possible that this change hasn't propagated. No, that's not doing it. There should be a way to set it as registered here. But I don't quite know how to do that. Okay, this bit is not interesting so I will go and figure this out and come back. Okay, I figured it out. It was simply because the reg values were never being assigned to from anywhere. It's another place where the optimizer is making my life painful. Anyway, I did remove the reg keywords from here and instead I'm defining my own explicit regs and then using a sign to assign the output to the regs. This is equivalent but this should be a little bit clearer. So this will not build because of that compilation issue so we're actually going to have to do a bit more work. So because we have four different address indices, zero to three for both inputs and outputs, we actually want to respond to a contiguous range of addresses which we can do easily enough with four. That's one, one, zero, zero like this. So decoded is now going to be true for any address from four, zero, four, one, four, two and four, three. And we are also going to add an index which is simply the bottom two bits of the address line. So we can now use index to decide which of our input and output values we want. We're going to do that here. So when the brother is reading, we wish to map one of the input values, which are control registers to the data bus. So we're going to do, put zero, put one, put two. So that should be sufficient for the read side of things. The right side of things is unfortunately a little bit more annoying because we have to interact with these registered values. And this leads us to the horrible issue of clock synchronization. We can't just assign values to these willy-nilly. We have to do it in sync with the rest of the system. So we do that with one of these blocks, not assign always. This will let you define a piece of code that effectively gets run every time clock, which is our system clock goes positive. And this is simple. If CPU is writing, then I've forgotten my languages. It's like this. If CPU is writing, then we wish to copy the value from data R here to one of these output regs. So if index equals zero, then multiple to not reg is data R. This operator is a assignment operator, whereas the equals sign here is an equivalent operator. This says that this is always going to be this. This says that the value in this gets copied to here whenever the execution of code flows through this point. I hope I'm getting my syntax right. The three reg is data R. Okay, let's see if this builds the syntax errors. The verilog syntax is kind of strange and annoying in almost every aspect. All right, now what's it complaining about? Output to reg is not driven by anything, but we are actually initializing it. I think do we need initial values? Is this going to work? It won't let me do this because this is an equivalent. It's saying that output to reg is always zero, therefore we cannot copy it here. Do we need a reset pin? I think we might. That would be annoying. Yeah, let's add a reset pin. So we go back to the symbol definition. We move all these down. Data input, we add one here. Reset. This is generally good practice anyway. Ah, we can't do a reset because we've used up all our control registers here. Is there a reset component? No, there is not. Okay, going away to sort this out. Okay, here we go. It's kind of vile, but it does seem to at least build. What we're doing here is saying that every time we get a write operation, or rather every clock cycle where the CPU is writing, then we assign all the register values to either the incoming data or the old value. That way that they all get assigned to every clock cycle and that seems to keep things happy. It does complain about unused pieces of the design. Let me just have a quick look. Interesting. Control cells 2 out of 4. Have I made a very stupid mistake? Put 0, 1, 2, and 3. 0, 1, 2, and 3. Index is a 4-bit value. So this is the report it's generated about what it's done. It's in tech mapping. This is nigh incomprehensible. Yeah, I think something's not right. So let's change that to not 3. Change that to 3. So index should now be 0, 1, 2, or 3. So what could it have? Why is it optimizing stuff out? Unless I made a mistake, it's still eliminated 2 of the control cells. See, the other thing we can do is to make the output here registered as well. But I don't think it's necessary. We would then have a ifCPU reading section here that updates it. So I think the... Okay, it has removed control reg2 and reg3. So is this actually wired up correctly? That is 2, 3, 0. There's net2, 3, 0. Okay, I think it's wired up correctly. So why is... I don't think it likes this for some reason. Okay, let's make that thing registered. So if CPU is reading, then... If index is 0, reg assigned to input 0. This is 1, this is 1, 2, 3. Let's see what it thinks of that. It does not like it. Okay, we've run out of space. That's because this is too complicated. Maybe the extra registered value isn't helping. So this has required it to synthesize 8 latches to hold the values. Now, there is a case of when... I'm going to go look that up. Okay, this is what the syntax for case looks like. Let's see if that actually produces more compact code. Looks like it does not. Okay, possibly it doesn't like the fact that there are four assignments here. Now, I can't remember where they're in very long case statements are expressions. But let's try... Let's see if it likes this. This way, there's one assignment which should be... Nope, it doesn't like that. Okay, well, let's try this again. This should do the same thing as my earlier code, but it's laid out differently. Okay, the extra registered value is clearly pushing things above the limit. So we can either drop down to three registers or try and make the original code work. I'm going to try and make the original code work. DataW2. So this... We do not need this anymore. We don't need this anymore. As I said earlier, this is not a very big FPGA-like thing. Whoops. Stop, stop, stop. Do not want to program it or the brother will crash. So are we going to get the same errors before? Unused pieces of the design have been optimized out. Yeah. Now, why is it doing that? 7 to 0, 7 to 0, 7 to 0, 7 to 0. I can force it not to optimize those out by setting values, which we're going to want to do anyway. So what's this going to do? Of course, they've been optimized out so these don't exist anymore. Ha! I think I figured it out. And this is going to be one of those bits where the Verilog people out there are going to be screaming at me. This is a two-bit value. This is a one-bit value. So index can only have values 0 or 1, which means that index equals 2 is never going to be true. So set that to that and then build it. And we are out of space. Fantastic. We run out of p terms, whatever a p term is. Okay, can we strip this down any? I bet there is a standard idiom for doing this, which I am going to go and find out. Okay, well, I couldn't make it fit at all, so I just decided to go down to two registers each. It does simplify the code quite a lot, and it puts us comfortably under the p-term limit. It went from 98 down to 50. So the extra two registers was clearly using almost exactly half of the p-term use, so whatever a p-term is. Anyway, there's actually a better way to do this, which is to use one of... Where is it? Which is to use a data path component, which I do not actually seem to find offhand. It's somewhere around. The data path tool is basically a miniature CPU, and you can use this tool to configure it. It will also show up as a component with lots of stuff on it. Is it under logic? I've used it in the past. It's got to be here somewhere. It's got a whole ton of functionality, including FIFOs, the ability to do computations, all that sort of stuff, and it would make doing this fairly straightforward, except it's a complete pain in the ass to use, particularly if you want to do parallel data input and output, which I am doing here. I had to do that for the flux engine port, and that was grim. I spent so much time trying to fix it, that eventually someone else fixed it for me. This chip has four of them, so if I could figure out where they were, that would help. Anyway, this now builds... It's producing a warning here. Setup time violation. Now, this is because it's taking too long for a change to propagate through the schematic. As a result, by the time the change propagates all the way through the logic, then something else might have changed, and there's a timing analysis here, and here you can see that it's saying that the current logic, the maximum frequency supported is 17 MHz, but I've asked for 29. Now, where is that happening here? This is from the control register to one of these nets. Okay, it's 232. So I bet 232 is one of these. It's the... I bet it's taking too much time going through here. There are a number of ways around that, but the simplest is to simply reduce the speed of the machine. Come on, standard. If we go down to 14.5 MHz, then this is the clock used by the UART, which should be in range. Can you set these to anything other than integers? I bet you can't. What does 13 do? That puts it more out of range, about 15. That's closer. Okay, back to the schematic. Let's take a look at the UART, which is over here. 115.2. That is actually out of range, and it said that 17 was... That's even more out of range. Yeah, it said that 17 was the maximum frequency. Now, there are ways around this. I wonder, could we simplify this code? I think we probably can. Let's take this back to 29, and let's take a look at that very log again. Now, the reason for this chunk is so that... If you look at the schematic, actually, the outputs here remember their values and continue to assert them so that the status registers here always read the last value output. This will make the software side of things easier. However, we can probably do this all in software. We just need to be able to read the value out of the register quickly enough. What we would do is whenever the brother tries to write to one of the output ports, we would raise an interrupt. Then the CPU would have to service the interrupt quickly enough to read the value from the status register. The status register would now be wired directly to the data bus. It would have to read the value quickly enough to capture the value before the end of the bus transaction. Is that plausible, I wonder? It's a rather small number of cycles. Let's take another look at this. Excuse me one second. Small insects walking across my keyboard. Apparently my computer's got bugs in it. Now, there is this wait cycle thing. During the read or write cycle, the external hardware is allowed to assert weight and halt the CPU until something happens. I don't know how long it's allowed to wait for. I'd have to go and look into that. I bet that trying to wait indefinitely would cause the machine to crash as the DRAM stops being refreshed and all the data expires. Let's not go there. Introduces wait cycles. Low at the falling edge. We could probably insert some, I don't really fancy that idea. The other thing is we can change the clock speed of the UART to be more friendly to a lower clock speed. Let's try 14. This is out of range. That is still out of range. Still out of range. That's in range. I don't think I want to run this thing at 19.2 kiloboard. That is quite slow. It's a Z80, that's fine. That's probably going to be... Yeah, that's absolutely fine. I'm a little bit surprised that the clock generation isn't a bit cleverer than that. We can tell it to pull the clock from somewhere else. At least I think we can. So we could generate our own clock. Let's just leave it like that. That is simple. So now if we build it, hopefully we should not get the timing error. The other advantage of doing this is it doesn't actually matter. Excellent, it's clean. This one warning is these, which I'm no longer using. So reg0 contains hex12, reg1 contains hex13, let's program that and head on over to the workbench. Okay, so the machine has not crashed while we've been fiddling with it. So let's run the program and it should produce 12. 12 it is. Okay, let's change this print get or 1. Okay, and run it. And this should get 34, I think it was. That's not right. 19. Maybe 13 from looking at the other monitor. 18 is wrong too, actually. Intriguing. Most intriguing. I figured out what the problem was after about 45 minutes of debugging and rewriting everything several times and it's pretty straightforward. If I run this, we get 18 and 19. Which are the wrong values? But what happens if I look at what the hex of 18 is and the hex of 19? Yes, they are in fact the right values. I was just printing them in the wrong place. So this should be hex of 40 and hex of 41 and 18. Yes, 12 and 13 are the right values. Right. It is currently 10 part midnight and as you can tell I'm getting a bit tired. But anyway, we now have nearly all, I think all of the Berrylog stuff working. So I'm going to take a break here and then next time I'm going to work on the actual software side of things. So that'll be nice.