• Content count

  • Joined

  • Last visited

Community Reputation

69 Excellent

1 Follower

About Arnadath

  • Rank
    Junior Member

Recent Profile Visitors

140 profile views
  1. @Q the Platypus hey. It seems that i will have to freeze my project for more than the afforementioned 2 weeks. You seem interested in digital stuff. Would you like to continue it? I have too many real life stuff atm and got in the forum today to ask if anyone would like to make progress on it.
  2. One interesting thing i have noticed is that sounds can become a huge cpu hog for this game, after a certain threshold. I think the game tries to handle all sound sources instead of dropping channels to avoid buffer overflows.Also unity's sound effects like reverb are abysmal in efficiency. Not noticeable in bigger systems with a lot of RAM, but very noticeable in older computers
  3. A 4 day counter

    Welll... it does. Have you even tried it?
  4. v1.899 is now out and about. I changed a little the design philosophy to enable us to have better synchronisation among components.Specifically, the control bus now is composed of 9 lines. The upper 5 bits, enumerate operands and registers within our cpu, the 2 next bits are for passing parameters, the 8th line is for internal interrupts and the 9th (the one that has the jagged shape) is the clock Now, as of the current state of the machine, we don't yet fetch opcodes from memory, although we are in a state that we could do so. That is, because i haven't programmed yet all the procedures. But then again, programming the procedures is more time consuming rather than brain consuming. Let's see how it's done Step one would be to fetch an instruction from the ram address, pointed to by the program counter. (The fetch structure is existant, but not yet utilised and i haven't programmed the procedure as of yet). Next step is to decode the instruction into internal procedures. Those internal procedures are like a hardcoded 1-4 step algorithm that tells the machine what to do exactly. And it makes constructing a mnemonic table, more intuitive. Instructions are 8 bit words. MOV STRUCT MOV instructions start with a 00. The next 3 bit's correspond to the enumerated source register and the last 3 bits correspond to the enumerated destination register. The register enumeration, is as following: ENUM || REGISTER 00 000 NULL 00 001 ALL FLAGS 00 010 AX 00 011 BX 00 100 Σ (sigma accumulator) 00 101 IObuf (Not a register, just denotes direction of the data bus as input/output from/to ram and peripherals) 00 110 IP(index pointer) 00 111 NULL (reserved for SP) 10 00X PC* *Note: This is a special register. We cannot address it directly with a mov command. When fully implemented in the future, it's default behaviour will be to increase it's value by one before every fetch step, except if the last instruction was a conditional jump that succeded, in which case we load the value from the IP to which we have loaded the address beforehand. The full functionality is not yet implemented, because i have to consider some small timing details. Behavioural of registers: A register that is to be a source, should be set so,during negative clock. At the positive edge of clk, it will enable output to the data bus and will disable itself at the next positive edge. A register that is to be a destination, should be set so during positive clock. At the negative edge of clk, it will write into itself whatever value it get's from the data bus. Unlike being a source, the procedure of writing lasts one tick instead of the input being enabled untill the next negative edge To set anything as source/dest, set your enumerator, and set parameter1 to '1' for dest or '0' for source. Give it 3 ticks to settle In the AX/BX register, set parameter0 to '1' to set them as sources to DATA bus. Also the behaviour of setting them as sources for the ALU is inverted. The output is normally enabled. If you set parameter1 to '0', the output will be disabled untill the next positive edge. This is to output only one register in some specific instances. ARITHMETIC/LOGIC STRUCT Components inside the ALU, are also enumerated in the same way registers are enumerated ENUM || FUNCTION 01 00X "CONCATENATED NOT'S" (NOT A/NOT B/ INTERNAL NOT A/INTERNAL NOT B) 01 010 ADD 01 011 CMP (as numeric) 01 100 BITWISE 01 101 BITSHIFT/BITROTATE 01 110 NULL (reserved for special operands in future) 01 111 NULL (reserved for special operands in future) Components in the ALU are ALWAYS destinations, since the input to all of them is automatically AX and BX. Remember the part of the extremely fast unconcious brain? Well, this is the ALU. It knows everything beforehand and it's up to us which answer we want to route to AX/BX or Σ. Ιν μοστ ψασεσ, ςε ςαντ το λοαδ ιντο ΑΧ ορ ΒΧ, βθτ ςηεν ςε ηαωε α ΞΜΠ φθνψτιον ιν ηανδ, ςε ςαντ το λοαδ ιτ ιντο τηε S register so as to set our flags. This is also the difference between Comparing to get a numeric answer and comparing to prepare a jump. For adding and comparing, we just need to set parameter1 to '1' (no need to normally, but some error correction never hurt anyone ) and the ouput will be enabled from positive edge until the next positive edge, just like being a destination register. For bitwise operations, param1 and param0 select the operation. 00 is null, 01 is or, 10 is XOR and 11 is AND For the bitshift operation, param1 selects wether we Roll or Shift and param0 selects direction left/right. The bitshifter is set so that it bitshifts directly the value of A by the last 3 bits of B (much faster than shifting one by one for x times). When it's down, it will output an internal interrupt to let the controller know it's done. JMP's STRUCT Note:The jmp struct and it's mnemonics, will be more thoroughly explained in next update were it will be acctually implemented, but you can use it right now if you can write the procedure for it! If you follow the output path of the flag's, you'll see it ends up in some gates and then in a bunch more cables that end up in the program counter part Zero flag raised = Lower than Zero or Equality flag raised = Lower than or Equal Equality Flag = Equal Not Equality Flag = Not Equal Equality or Greater Flag raised = Greater than or Equal Greater Flag raised = Greater than Carry flag raised = Jump Carry (to implement Jump Not Carry, what we do is to Jump Carry back to the start of the function and if there isn't carry and we can continue, we load another value in the IP and jump uncoditionally in the next step. For Now, because later on i'll make a direct Jump not carry opcode) Unconditional Jump = Always '1'. FETCH AND PROCEDURE DECODING Let's assume that we just fetched an instruction from RAM. How do we decode it? Locate this part. The fetch register isn't connected to anything yet so it'll never interact with the data bus. You can set the hypothetical opcode values through those switches. You can also see the "MOV" procedure. The logic behind the procedures, is that we feed a 'step' line with 'HIGH' for 4 ticks and at the 3rd tick we toggle the state of clk so that the enumeration decoders have ample time to be set and can start routing the way we instruct them to route. 4 ticks is the minimal set time to have certainty, but you can increase it. Just append more OR's on every collumn of the "PLL" The way we generate the clock and the proc line will change, because there will be some cases were we need to slack it to have information certainty, but the way it is now, it'll give you the rough idea of our timing constraints. (Every enumeration decoder can, and should be isochronous with a set time of less than 4 ticks. Just something to keep in mind if you decide to change the enum decoders around.) But in the case depicted, we don't decode to MOV (all MOV's start with 00. Also 00000000 decodes to moving null to null and essentially means NOP).In this case, we decode for INC, which is this proc: We get 0101010X as fetched instruction. This decodes to INC. X is the register to put the answer to (0 = AX, 1 = BX) The first row contains two AND gates with one leg normally on. When they receive a signal that it's their step, they'll output '1' to Bit 2 and 0 of the control bus. This means 00001-01 which translates to (ENUM:All flags, PARAM: Raise Carry flag.) The next step is to 0001(NOT X)-01 which translates to (ENUM:The other register, PARAM: Disable output to internals) Next up is 0101010 which translates to (ENUM:ADD, PARAM:Enable) And lastly 0001( X )-10 which translates to (ENUM: The defined reguster, PARAM:WRITE). After we execute those steps, we are supposed to increase the program counter and fetch a new thing, but this is not yet implemented as i said before. So here you have it, The INC demo that we started with, but in it's final form. This is not the final form of the controller though. We need a better clock generator, because in some cases that have to do with arithmetic/logic functions, we need to give some more time for them to set. In edge cases, the ripple adder and the comparator, will need 7 ticks to set to the correct value and the bitshifter will do it's own thing and tell us when it's done. So we will need to 'slack' the clock in those steps. But this is for another time. That's all the new stuff i added. Those might seem more confusing than when we started, but trust me, it will all make sense in the end. Now, i will be kinda busy for the forseeable future (like 1-2 weeks) so i'll have little to no time to work on the cpu, but what can we do... If i want to continue doing cool stuff in ONI, i must secure food on my plate first. But by all means, you can add your own opcode decoders if you understood how to program a procedure. Hell, even post it here if you verified that it'll work. I'll be more than happy to credit you even for the smallest contribution. We are after all at the phase where everything is easy but just tedious and time consuming. This for now. See you later Arn Vortex v1.899.sav
  5. A 4 day counter

    Why not more compact?
  6. Judging by the picture, this will also work because your time critical path is 2 ticks.
  7. @Saturnus. Yep. Here is a version of your xor that won't produce this pulse We just confirm for nor condition before we confirm for nxnor condition.
  8. @Saturnus Short answer is no. They are unreliable substitute. A buffer gate for example, will change the output from off to on within one frame after receiving a 'true' in the input, but the transition from on to off, will last one frame, plus a game time check which means randomly 1 or 2 more ticks. Do this experiment in debug mode: Both filter and buffer gate are at 0.1 sec Just flick the switch while unpaused. The mechanism is set so that it skips the initial automation step, and counts how many automation steps takes for the "real time" transition to happen. In slow speed, you'll see the buffer gate will delay transiting randomly for 1 up to 2 steps. In the highest speed, it might take even more than 5 steps. Filter gate also expressses this eratic behaviour but it's only apparent in slow speed. The or gate will always transit at automation step, thus it will never ever change any of the outputs If you are trying to do synchronous automation and you utilize even one of them in your design, your system will always get out of whack pretty quickly.
  9. Both our designs have a problem, and it's the same problem. If you change the input from "00" to "11" there will be a 1 tick of '1' in the output. You can fix the behavioural by making the nor condition happen 1 tick later than the AND condition, with two OR gates in each input.
  10. Update v1.864 is now live. And It's a HUUUGE update. ====================changelog=================== Added a Σ register to accumulate the output of the ALU. Added carry, zero, equality and greater than flag Quadrupled the ram, from 8 to 32 byte and a 6-bit address bus which means we can address up to 64.byte ram. Added controls and decoders for all the circuitry so far. Also added a control matrix that reads program code. Also added a control bus (opcodes will be explained). Added synchronous disable for all operand outputs Removed the bcd decoder, but pretty soon, we'll be decoding through cpu. ================================================ The whole thing, looks like this now: Now, i have to warn you. The intensity of the switching, depending on what parts you are looking, can and will bring the audio engine down to it's knees. a.k.a if you switch from slow to fast speed at the wrong moment, you will hear some audio buffers overload. If you're lucky, this will stop after 3-4 seconds. If not, a black hole will eat your game. I didn't even bother reporting those crashes because i'm kind of sure as to why they happened. If you want to try to write your own program, here's the mnemonic table that i constructed so far: Register/flag actions BITMASK 6: X (Enable/ Disable out if refering to a register, Don't care if refering to a flag) 5: X(0 = Read, 1 = Write if refering to a register/ 0 = Rst, 1 = Set if refering to a flag) 4: X(0 if a register, 1 if a flag. Might swap in the future) 3: X(addr2) 2: X(addr1) 1: X(addr0) 0: 1 (for actions regarding an internal register or flag registers: addr2 | addr1 | addr0 0 0 0 0 Σ register 0 1 0 1 AX 0 1 1 0 BX 0 1 1 1 IO Buffer (Sets direction from/to Ram. Is not acctually a register) flags: addr2 | addr1 | addr0 1 0 0 0 Zero (ZF) 1 0 0 1 Equality (EF) 1 0 1 0 Greater than (GF) 1 0 1 1 Carry (CF) 1 1 0 1 AX to data bus (implies that AX is enabled and in 'read'. Won't produce serviceable interupt if set) 1 1 1 0 BX to data bus(implies that BX is enabled and in 'read'. Won't produce a serviceable interrupt if set). Interrupt and overflow flag TBD Arithmetic/Logic actions BITMASK 6: X (Synchronous disable of all ALU outputs. If set, it is implied that all other bits in the data bus are 0. Otherwise... problems) 5: X(1 = arithmetic function, 0 = logic function) 4: X(func1 3: X(func0 2: X(param1) 1: X(param0) 0: 0 (for actions regarding arithmetic or logic functions) Arithmetic | func1 | func0 1 0 0 NOT A to externals (data bus) param1 = Don't Care param0 = (Disable if 0, Enable if 1) 1 0 1 NOT B to externals(data bus) param1 = Don't Care param0 = (Disable if 0, Enable if 1) 1 1 0 ADD param1 = Don't Care param0 = (Disable if 0, Enable if 1) 1 1 1 BITSHIFT param1 = (rotate if 1, shift if 0) param0 = (left if 1, right if 0) Note: The bitshifter won't work yet because i forgot to connect a cable and i cannot find which one right now. But it works properly, i swear. Logic | func1 | func0 0 0 0 NOT A to internals (bitwise) param1 = Don't Care param0 = (A if 0, NOT A if 1) 0 0 1 NOT B to internals (bitwise) param1 = Don't Care param0 = (B if 0, NOT B if 1) 0 1 0 CMP param1 = Don't Care param0 = (Disable if 0, Enable if 1) Note: After you perform compare, write to Σ to get Equality and Greater than Flag. The Zero flag serves as a Less than indicator this way. The carry flag is raised if there is a Cout from the adder and will also produce a serviceable interrupt which i'll use in the future. Also the carry flag acts as the Cin for it. So if you want to increase by one without touching the other register, you can disable the register, raise the flag and perform the addition. 1 1 1 BitWise param1,param0 00 = Nothing 01 = OR 10 = XOR 11 = AND Won't get into further detail yet. The demo should be just the same counter it was the last time. Only this time it is an executable program running.this code in loop read A enable add write Σ disable add read Σ write Α Remember to always set your source first and then your destination when playing with registers to avoid accidental writes wherever you don't want to. Have fun. Arn Vortex v1.864.sav
  11. Duplicant Logic Eval

    So while i was working on the cpu, i had this fantastic idea, i'll use it to make a game. A game in my computer in my game in my computer. Crazy. Right? So i started making a '3rd person' puzzle solving game. The idea came from the vascilator ruins that have this small easy logic puzzles. Only the puzzles in this are a tad more advanced. This map has 4 puzzles so far and is a work in progress I'll post a walkthrough if needed but won't spoil anything for now. Sugestion: Toggle 'follow cam'. It helps A LOT with the immersion. Have fun Dupe Logic Eval.sav
  12. @impyre And not only. You can do really cool stuff with timings by arranging NOT's and OR's to specifically filter parts of your signal. I'm working now on this thing. I call it the 'pulse accumulator'. It detects if a signal went from 'off' to 'on' for 1, 2, 3 or 4 pulses and sets those 2 latches. Basically it's like an on-the-spot demultiplexer. And very easily cascadable to detect more pulses. The way automation works in this game, it's like every component is clocked to a global NOT gate connected to itself. And it's up to us to utilise it efficiently
  13. @Saturnus I see your point. And i won't debate wether somebody had a similar post before, nor will i debate that simplicity in your structures is of importance when it comes to you practical applications.But this thread is not about practical applications This post should be viewed in context of the designing prospects of digital circuits when it comes mainly to cramming more 'necessary' stuff together in a tightier space. Take this for example: This is an itterator circuit that drives the bit shifter/rotator. It is essentially something like this in higher languages: While(unsigned int i=x ; i<8 ; i++){ Produce_A_Pulse(); } Where x is anywhere from 0 up to 7 . Half the circuit is not gates, of which half of them are there for timing, and the rest to emulate other gates and solve our HUGE topological issues for the sacrifice of some speed. So take this whole post for it's "designing circuits" perspective, not it's practical in-game perspective.
  14. Yes, well, i expanded on the topic. I show you how to also make a XOR gate
  15. Not at all an artifact. All logic circuitry is build upon NOT gates and what i suppose you could call YEAH gates. We just no no, whenever we cannot yes.