Last visit was: Wed Oct 09, 2024 8:22 pm
|
It is currently Wed Oct 09, 2024 8:22 pm
|
Author |
Message |
commodorejohn
Joined: Wed Oct 23, 2019 1:52 am Posts: 9 Location: Sacramento, CA
|
I've had a vague interest in stack-oriented CPU designs for a while, but it took me a while to settle in on an architecture that seemed flexible-yet-achievable enough for a potential hardware project down the road; after a while of fiddling around with different approaches, I ended up with something inspired primarily by the DG Nova architecture (and the PDP-8's OPR instructions,) in the sense of trying to pack a large number of functions into the primary opcode formats and choosing sub-operations that make it possible to synthesize additional operations out of simpler ones. I'd like to do a hardware implementation at some point, but for the moment I'm using it as a VM architecture for a little Parallax Propeller project I'm working on; after much tinkering, I've gotten the primary instruction groups down to 2.8 and 3.6 µs. Anyway, on to the description: This is a 16-bit, byte-addressable CPU using two stacks in main memory (hardware implementation would likely include some kind of caching.) There are four CPU registers: the Instruction Pointer (IP,) the Interrupt Mask/Carry (MSK,) and the Data and Call Stack Pointers (DSP and CSP.) The top few stack items are referred to as pseudo-registers TOS (top-of-stack, item #0) NOS (next-on-stack, item #1) NNS (next-next-on-stack, #2,) and TCS (top-of-call-stack.) Instructions and stack items are a full 16-bit word; the address registers (IP, DSP, and CSP) implement only the 15 MSBs and are therefore always fixed to a word address. The instruction groups are as follows: Code: FEDCBA9876543210 ---------------- 0NNNNNNNNNNNNNNN Push constant: N Number (15-bit unsigned integer) 1000JRFFS<>NCCI! Arithmetic operations: J Jump (IP <- TOS) R Prepare for Return (TCS <- IP) FF ALU Function (0: Add w./Carry, 1: AND, 2: OR, 3: XOR) S B-operand Source (0: Consume NOS, 1: Constant 0xFFFF) <> Rotate TOS (0: No, 1: Right, 2: Left, 3: Swap bytes) N Alter Carry if Negative (0: Always alter, 1: Only if TOS < 0) CC Alter Carry (0: No, 1: Complement, 2: Clear, 3: Set) I Increment TOS (0: No, 1: Increment TOS) ! Complement TOS (0: No, 1: Ones-complement TOS) 1001B+-<>sIDMCcb Stack/control operations: B Break to software interrupt handler + Duplicate TOS - Drop TOS <> Transfer TOS/TCS (0: None, 1: TOS -> TCS, 2: TOS <- TCS, 3: TOS <-> TCS) s Save/Load Registers on call stack (0: Load, 1: Save) I Save/Load IP (0: No, 1: Yes) D Save/Load DSP M Save/Load MSK C Swap TOS w./CSP c Swap TOS w./NNS b Swap TOS w./NOS 1010BXIOOOOOOOOO Load Byte/Word B Byte (0: Word, 1: Byte) X Extend (0: No, 1: Yes) I Index source (0: Consume TOS, 1: IP) O Offset (9-bit byte offset, sign-extended) 1011BXIOOOOOOOOO Store Byte/Word 1100OOOOOOOOOOOO Branch if Zero (Consume TOS and branch if zero) O Offset (12-bit word offset, sign-extended) 1101OOOOOOOOOOOO Branch if Positive 1110OOOOOOOOOOOO Branch if Negative 1111OOOOOOOOOOOO Branch Always As you can see, the two primary instruction groups (besides the constant-push operation) are composed of multiple fields/flags for different sub-operations; these are (mostly) executed in-order, LSB-first. (Exceptions are the modifier flags for other fields - the Alter Carry if Negative flag and the load/save switch for register saving and retrieval. The load/save operations also operate in reverse order when saving, so that grouped save and restore operations record and restore the same operating context.) Any non-negative integer is immediately pushed to the stack as-is; values from 0x8000 - 0xFFFF can be constructed by pushing the logical or additive inverse and then ones- or twos-complementing it using the first two sub-operations in the arithmetic group. This isn't set in stone yet - I've yet to do any serious coding tests, and there's a few things I'm not entirely sure of (the order of operations between carry-manipulation, rotate-with-carry, and ALU operation, particularly.) Particular details are also implementation-dependent at the moment (the Propeller implementation keeps TOS entirely in register and DSP always points at NOS, which I don't care for, but which resulted in a significant speed-up,) and there's no specified I/O model (the Propeller implementation, again, uses memory-mapped I/O for convenience's sake, but if I ever do a hardware implementation I'd probably try to sneak port-mapped I/O in there by cannibalizing the mildly nonsensical write-byte-sign-extended and read-word-sign-extended instruction combinations.) I do have the Propeller implementation pretty much completed, but I haven't tested it yet...
_________________ "'Legacy code' often differs from its suggested alternative by actually working and scaling." - Bjarne Stroustrup
|
Wed Oct 23, 2019 5:36 am |
|
|
yeti
Joined: Fri Oct 20, 2017 7:54 pm Posts: 8
|
Quote: I do have the Propeller implementation pretty much completed, but I haven't tested it yet... I'm all ears!
_________________ "Stay OmmmMMMmmmPtimistic!" — yeti "Logic, my dear Zoe, merely enables one to be wrong with authority." — The 2nd Doctor "Don't we all wait for SOMETHING-ELSE-1.0?" — yeti
|
Wed Oct 23, 2019 7:27 am |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1799
|
yes, sounds great!
|
Wed Oct 23, 2019 9:28 am |
|
|
commodorejohn
Joined: Wed Oct 23, 2019 1:52 am Posts: 9 Location: Sacramento, CA
|
As mentioned, this has been in no way tested yet (really need to get set up with a Propeller toolchain and simulator...) But here it is anyway: Code: ; Stack-CPU instruction set interpreter for Parallax Propeller ; Alternate implementation - no NOS caching, TOS is register-only, and DSP ; points to NOS; want to try and cut down the amount of juggling needed. org 0 doALU: ; Handle group 0x8 (ALU) opcodes ; Initial branch-off to init code - replaced with the first instruction of ; the ALU group handler routine during init time. jmp #doInit ; Above to be replaced with: ; test opcode, #1 wz ; is the ! bit set? ; Here follows the rest of the group 0x8 code. if_nz xor tos, const_ffff ; if yes, ones-complement TOS test opcode, #2 wz ; is the I bit set? if_nz add tos, #1 ; is yes, increment TOS ; before checking the carry bits, check the only-if-negative flag test opcode, #16 wz ; is the if-negative flag set? if_nz test tos, const_8000 wc ; if yes, is TOS negative? if_nz_and_nc andn opcode, #12 ; if not, clear the carry bits test opcode, const_0400 wc ; are we saving IP to TCS? if_c sub csp, #2 ; if yes, decrement CSP if_c wrword ip, csp ; and save it to the stack test opcode, #8 wz ; check the carry bits if_nz mov carry, #0 ; CC %1x: clear carry test opcode, #4 wz if_nz xor carry, #1 ; CC %x1: complement carry ; new approach: ALU function happens before the shift/rotate, Nova-style test opcode, #128 wz ; is the ALU source 0xFFFF? if_nz mov tmp, const_ffff ; if yes, use 0xFFFF if_z rdword tmp, dsp ; if no, get the current NOS if_z add dsp, #2 ; if we're using NOS, increment DSP test opcode, const_0600 wc ; check the ALU operation bits test opcode, const_0400 wz ; Z clear if %10 or %11, C set if %01 or %10 if_z_and_nc add tos, tmp ; FF %00: add with carry if_nz_or_c shl carry, #16 ; if no add, carry-in goes to carry-out if_z_and_c and tos, tmp ; FF %01: AND if_nz_and_c or tos, tmp ; FF %10: OR if_nz_and_nc xor tos, tmp ; FF %11: XOR add tos, carry test opcode, #64 wc ; check the rotate bits test opcode, #32 wz if_nc_and_z jmp #doRotate ; <> % 11: swap bytes test tos, const_10000 wc ; copy carry-out to Propeller carry if_nc_and_nz mov tmp, tos ; make a copy if_nc_and_nz shl tmp, #16 ; shift it left if_nc_and_nz or tos, tmp ; and combine them if_nc_and_nz rol tos, #8 ; and rotate left rotDone: and tos, const_ffff ; clear any extraneous MSBs if_c mov carry, #1 ; copy carry-out to carry flag if_nc mov carry, #1 test opcode, const_0800 wz ; are we jumping? if_nz mov ip, tos ; if yes, copy TOS to IP if_nz rdword tos, dsp ; and bump NOS to TOS add dsp, #2 ; and point DSP at new NOS jmp #doNext doRotate: if_z test tos, const_10000 wc ; <> %10: rotate left if_z rcl tos, #1 ; shift it left if_z test tos, const_10000 wc ; copy carry-out to Propeller carry if_nz shr tos, #1 wc ; <> %01: rotate right jmp #rotDone const_10000 long $10000 const_ffff long $ffff const_ff00 long $ff00 const_8000 long $8000 const_7fe0 long $7fe0 const_0800 long $800 const_0600 long $600 const_0400 long $400 const_0200 long $200 const_rdbyte rdbyte tos, tmp const_rdword rdword tos, tmp const_wrbyte wrbyte tos, tmp const_wrword wrword tos, tmp const_doALU test opcode, #1 wz tos long 0 ; Top-of-stack pseudo-register carry long 0 ; Carry flag mask long 254 ; Interrupt-enable mask res ($40 - $) ; pad to 0x040 (already filled up!) doControl: ; Handle group 0x9 (control/stack) opcodes mov tmp, tos ; save TOS just in case mov tmp2, dsp ; prepare a pointer to NNS add tmp2, #2 test opcode, #1 wz ; is the swap-B bit set? test opcode, #2 wc ; is the swap-C bit set? if_nz rdword tos, dsp ; if swap-B is set, bump NOS to TOS or carry, mask ; prep mask/carry register just in case mov tmp3, tos ; save the current TOS if_nz wrword tmp, dsp ; if swap-B is set, push TOS to NOS test opcode, #64 wz ; is the save bit set? if_nz jmp #saveRegs ; if yes, save registers to the call stack rdword tos, tmp2 ; bump NNS to TOS test opcode, #32 wz ; are we loading IP? if_nc mov tos, tmp3 ; restore TOS if we did that wrong above if_c wrword tmp3, tmp2 ; if swap-C is set, push TOS to NNS test opcode, #4 wc ; is the swap-CSP bit set? if_c xor tos, csp ; if yes, swap TOS & CSP if_c xor csp, tos if_c xor tos, csp test opcode, #16 wc ; are we loading DSP? mov tmp, dsp ; save DSP in case we need to restore it later if_nz rdword ip, csp ; if we're loading IP, pop it from the call stack if_nz add csp, #2 ; and increment CSP test opcode, #8 wz ; are we loading M? rdword dsp, csp ; if we're loading DSP, pop it from the call stack if_c add csp, #2 ; and increment CSP if_nc mov dsp, tmp ; restore DSP if we did that wrong if_nz rdword carry, csp ; if we're loading M, pop it from the call stack if_nz add csp, #2 ; and increment CSP if_nz mov mask, carry ; and separate the mask and carry fields saveRegsDone: test opcode, #384 wc ; check the stack-transfer bits test opcode, #256 wz ; %00: none, %01: TOS-TCS, %10: TCS-TOS, %11: swap if_c_and_nz jmp #fromTCS if_nc_and_nz jmp #swapStacks ; <> %01: push TOS to TCS rdword tmp, dsp ; get NOS in case we need it if_c_and_z add dsp, #2 ; increment DSP if_c_and_z sub csp, #2 ; decrement CSP if_c_and_z wrword tos, csp ; push TOS to TCS if_c_and_z mov tos, tmp ; bump NOS to TOS andn mask, #1 ; fix mask in case it was loaded transferDone: and carry, #1 ; fix carry in case it was loaded nop ; was a pointless instruction test opcode, const_0600 wc ; check the drop/dup bits test opcode, const_0400 wz ; Z clear if %01 or %11, C set if %01 or %10 if_nz rdword tos, dsp ; if dup or drop/dup, set TOS to NOS if_c_and_z sub dsp, #2 ; if dup, decrement DSP if_c_and_nz add dsp, #2 ; if drop, increment DSP if_c_and_z wrword tos, dsp ; if dup, set NOS to TOS test opcode, const_0800 wz ; is the break bit set? if_nz mov ip, breaker ; if yes, point IP to SWI service address ; Control group falls through to: doNext: rdword opcode, ip ; get next instruction test mask, ina wz ; check enabled interrupt sources if_nz jmp #doInterrupt ; if anything's firing, address it add ip, #2 ; increment IP shr opcode, #15 wz,nr ; is the MSB clear? if_z jmp #doConstant ; if yes, it's a 15-bit constant mov tmp, opcode ; if no, turn the opcode into a dispatch address shr tmp, #12 ; move the group-select bits all the way right shl tmp, #6 ; move them back into position (clear the rest) jmp tmp ; jump to the indicated address ip long 0 ; Instruction Pointer register dsp long 0 ; Data Stack Pointer register csp long 0 ; Call Stack Pointer register ; 1 free word res ($80 - $) ; pad to 0x80 doLoad: ; Handle group 0xA (load) opcodes mov tmp, opcode ; copy the opcode to turn it into an offset shl tmp, #23 ; sign-extend the offset asr tmp, #23 test opcode, const_0800 wc ; is the byte bit set? if_nc movi :read, const_rdbyte ; if yes update the instruction if_c movi :read, const_rdword ; if no, update it the other way test opcode, const_0200 wz ; is the index-from-TOS bit set? if_z sub dsp, #2 ; if no, decrement DSP if_nz add tmp, tos ; if yes, add TOS to offset if_z wrword tos, dsp ; if no, push TOS down to NOS if_z add tmp, ip ; and add IP to offset test opcode, const_0400 wz ; is the sign-extend bit set? :read rdword tos, tmp ; fetch the value if_c and tos, #255 ; if the byte bit is set, clear the MSBs if_nz test tos, #128 wc ; if we're sign-extending, test the byte MSB if_nz muxc tos, const_ff00 ; and copy it to the MSBs jmp #doNext swapStacks: ; <> %11: swap TOS and TCS rdword tmp, csp ; get TCS andn mask, #1 ; fix mask in case it was loaded wrword tos, csp ; push TOS to TCS mov tos, tmp ; push TCS to TOS jmp #transferDone fromTCS: ; <> %10: push TCS to TOS andn mask, #1 ; fix mask in case it was loaded rdword tmp, csp ; read TCS add csp, #2 ; increment CSP sub dsp, #2 ; decrement DSP wrword tos, dsp ; push TOS to NOS mov tos, tmp ; pop TCS to TOS jmp #transferDone saveRegs: ; load registers from the call stack rdword tmp, tmp2 ; get NNS if_nc mov tmp3, tmp ; if swap-C is clear, push NNS back to NNS if_c mov tos, tmp ; if swap-C is set, bump NNS to TOS wrword tmp3, tmp2 ; store the appropriate value of NNS back test opcode, #4 wc ; is the swap-CSP bit set? if_c xor tos, csp ; if yes, swap TOS & CSP if_c xor csp, tos if_c xor tos, csp test opcode, #8 wz ; are we saving M? if_nz sub csp, #2 ; if yes, decrement CSP if_nz wrword carry, csp ; if we're saving M, put it on the call stack test opcode, #16 wc ; are we saving DSP? if_c sub csp, #2 ; if yes, decrement CSP if_c wrword dsp, csp ; if we're saving DSP, put it on the call stack test opcode, #32 wz ; are we saving IP? if_nz sub csp, #2 ; if yes, decrement CSP if_nz wrword ip, csp ; and put it on the call stack and carry, #1 ; restore carry to normalcy jmp #saveRegsDone doConstant: ; push 15-bit constant to TOS sub dsp, #2 ; decrement DSP wrword tos, dsp ; push TOS to NOS mov tos, opcode ; place the constant in TOS rdword tmp, ip ; delay to align with 0.4 us "cycle time" jmp #doNext ; 11 free words res ($c0 - $) ; pad to 0xC0 doStore: ; Handle group 0xB (store) opcodes mov tmp, opcode ; turn the opcode into an offset shl tmp, #23 ; sign-extend the offset asr tmp, #23 test opcode, const_0200 wc ; is the index-from-TOS bit set? if_c add tmp, tos ; if yes, add TOS to the offset if_c rdword tos, dsp ; and bump NOS to TOS if_nc add tmp, ip ; if no, add IP to the offset test opcode, const_0800 wz ; is the byte-write bit set? if_nz movi :write, const_wrbyte ; if yes, update the instruction test opcode, const_0400 wz ; is the sign-extend bit set? if_nz test tos, #128 wc ; if yes, sign-extend the LSB if_nz muxc tos, const_ff00 :write wrword tos, tmp ; store the item to memory at the specified address movi :write, const_wrword ; reset the instruction to default if_c add dsp, #2 ; if index-from-TOS is set, increment DSP rdword tos, dsp ; bump NOS or NNS to TOS add dsp, #2 ; and increment DSP jmp #doNext doInit: ; do initial setup for this CPU core mov doALU, const_doALU ; overwrite the initial jump instruction mov mask, #0 ; disable all maskable interrupts mov ip, #32 ; initialize IP to the shared reset location cogid breaker ; get the ID of this cog mov tos, breaker ; initialize TOS to the cog ID shl breaker, #2 ; turn it into a quad-word index ; set up the stacks at the top of Propeller RAM mov dsp, const_7fe0 ; initialize DSP to 0x7FE0 - (ID * 4 words) sub dsp, breaker mov csp, const_8000 ; initialize CSP to 0x8000 - (ID * 4 words) sub csp, breaker rdword tmp, ip ; delay to align with 0.4 us "cycle time" jmp #doNext ; 34 free words res ($100 - $) ; pad to 0x100 doBranchIfZero: ; handle group 0xC (branch-if-zero) opcodes test tos, const_ffff wz ; is TOS zero? rdword tos, dsp ; bump NOS to TOS add dsp, #2 ; increment DSP shl opcode, #20 ; sign-extend the offset asr opcode, #19 ; shift it down to a word offset if_z add ip, opcode ; if TOS was zero, branch rdword tmp, ip ; delay to align with 0.4 us "cycle time" jmp #doNext doInterrupt: ; identify and dispatch interrupt handler mov tmp, mask ; get a copy of the interrupt mask or mask, carry ; combine mask/carry for saving and tmp, ina ; mask out any interrupts we're ignoring sub csp, #2 ; decrement CSP wrword mask, csp ; save M to the stack sub csp, #2 ; decrement CSP mov tmp2, #254 ; prepare to mask out lower-priority interrupts wrword ip, csp ; save IP to the stack test tmp, #2 wc,wz if_c mov ip, #1 wz test tmp, #4 wc if_c_and_z mov ip, #2 wz test tmp, #8 wc if_c_and_z mov ip, #3 wz test tmp, #16 wc if_c_and_z mov ip, #4 wz test tmp, #32 wc if_c_and_z mov ip, #5 wz test tmp, #64 wc if_c_and_z mov ip, #6 wz if_z mov ip, #7 shl tmp2, ip ; shift the mask-mask into place shl ip, #2 ; turn the count into a longword index add ip, #32 ; and point it to the interupt dispatch table andn mask, tmp2 ; mask out lower-priority interrupts jmp #doNext ; 30 free words res ($140 - $) ; pad to 0x140 doBranchIfPositive: ; handle group 0xD (branch-if-positive) opcodes test tos, const_8000 wc ; is TOS negative? test tos, const_ffff wz ; is TOS non-zero? shl opcode, #20 ; sign-extend the offset asr opcode, #19 ; shift it down to a word offset if_nc_and_nz add ip, opcode ; if TOS is non-negative and non-zero, branch rdword tos, dsp ; bump NOS to TOS add dsp, #2 ; and increment DSP nop ; delay replaces useless instruction jmp #doNext ; 55 free words res ($180 - $) ; pad to 0x180 doBranchIfNegative: ; handle group 0xE (branch-if-negative) opcodes test tos, const_8000 wz ; is TOS negative? rdword tos, dsp ; bump NOS to TOS add dsp, #2 ; increment DSP shl opcode, #20 ; sign-extend the offset asr opcode, #19 ; shift it down to a word offset if_nz add ip, opcode ; if TOS was zero, branch rdword tmp, ip ; delay to align with 0.4 us "cycle time" jmp #doNext ; 56 free words res ($1c0 - $) ; pad to 0x1C0 doBranch: ; handle group 0xF (branch-always) opcodes shl opcode, #20 ; sign-extend the offset asr opcode, #19 ; shift it down to a word offset add ip, opcode ; branch jmp #doNext ; 44 free words
_________________ "'Legacy code' often differs from its suggested alternative by actually working and scaling." - Bjarne Stroustrup
|
Wed Oct 23, 2019 4:55 pm |
|
|
commodorejohn
Joined: Wed Oct 23, 2019 1:52 am Posts: 9 Location: Sacramento, CA
|
Update: progress on this has been slow, I'm afraid, as I've been busy with several other projects and general life stuff. However, I did end up reworking the design a bit, replacing the push-immediate opcode range with a jump-to-subroutine immediate range (where every even opcode is a call to that address) and reshuffling the opcode format accordingly. This makes subroutine-threaded code compact and simple, which is nice for Forth purposes - most word definitions will consist almost entirely of bare addresses. Memory addressing got revised a bit as well - adding zero-indexed and stack-indexed addressing (with unsigned displacements) to the (signed) IP-relative and TOS-relative modes; this added flexibility should help make up for the loss of immediate constants. The port-mapped I/O scheme has also been discarded in favor of memory-mapped. I haven't tried updating the Propeller implementation to reflect this yet as I'm more interested in/focused on the idea of doing it in discrete logic. I have, however, almost finished writing a simulator in which I can try writing some code for this beast and see how I like it. The simulator core is pretty well done; I'm just working on the interface at this point. I've also put up an official-ish not-very-good-ish page at: http://commodorejohn.freeshell.org/
_________________ "'Legacy code' often differs from its suggested alternative by actually working and scaling." - Bjarne Stroustrup
|
Tue Nov 02, 2021 4:27 pm |
|
|
oldben
Joined: Mon Oct 07, 2019 2:41 am Posts: 649
|
On the other side of the coin, you have something like a Tiny Pascal as stack machine. Small C is almost stack design, being a simple recursive decent compiler. Here a compact encoding is needed as the compilers are very brain dead. Code: B=C+1; lea B push B ld C push C ld #1 push 1 add store **(tos++) = *(tos++) A real compiler NON RISC LD C ADD #1 ST B
|
Thu Nov 04, 2021 6:41 am |
|
|
commodorejohn
Joined: Wed Oct 23, 2019 1:52 am Posts: 9 Location: Sacramento, CA
|
Signs of life! Code: [stackcpu] ./a.out stacksim - 16-bit stack CPU simulator. (C)2021 commodorejohn. Q to quit, H for help.
. hello.core load . 66 0 dis @000000: @010405 000100 @Z LDW @000002: @020003 DUP @000004: @060005 000000 @TOS LDB @000006: @020003 DUP @000010: @100141 000030 BEQ @000012: @015007 001200 @Z STW @000014: @001421 INC -1 AND @000016: @177717 177762 BRA @000020: @000000 000000 JSR @000022: @000000 000000 JSR @000024: @000000 000000 JSR @000026: @000000 000000 JSR @000030: @000000 000000 JSR @000032: @000000 000000 JSR @000034: @000000 000000 JSR @000036: @000000 000000 JSR @000040: @010003 DRP @000042: @010003 DRP @000044: @040003 BRK @000046: @000000 000000 JSR @000050: @000000 000000 JSR @000052: @000000 000000 JSR @000054: @000000 000000 JSR @000056: @000000 000000 JSR @000060: @062510 062510 JSR @000062: @066154 066154 JSR @000064: @026157 000615 @SP STB @000066: @073440 073440 JSR @000070: @071157 000232 @TOS STW @000072: @062154 062154 JSR @000074: @000041 PCP NOS ADD @000076: @000000 000000 JSR @000100: @000060 000060 JSR . 0 go Hello, world! Interrupt raised.
IP: @000044 DSP: @000576 CSP: @000700 MSK: @177776 CB: @0 .
_________________ "'Legacy code' often differs from its suggested alternative by actually working and scaling." - Bjarne Stroustrup
|
Mon Nov 22, 2021 4:42 pm |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1799
|
A milestone - well done!
|
Mon Nov 22, 2021 4:53 pm |
|
|
commodorejohn
Joined: Wed Oct 23, 2019 1:52 am Posts: 9 Location: Sacramento, CA
|
And, after a whole bunch of cleanup, correction, and commenting, here's the source for the initial version of the simulator. It's as complete as the architecture is at the moment (among other things, the details of interrupt handling have yet to be defined, so the BRK instruction just halts the simulation.) Released under the "do whatever" license ;)
You do not have the required permissions to view the files attached to this post.
_________________ "'Legacy code' often differs from its suggested alternative by actually working and scaling." - Bjarne Stroustrup
|
Fri Dec 10, 2021 1:52 am |
|
|
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1799
|
Well done, and thanks for sharing!
|
Fri Dec 10, 2021 7:45 am |
|
|
commodorejohn
Joined: Wed Oct 23, 2019 1:52 am Posts: 9 Location: Sacramento, CA
|
Update: I've more or less worked out how traps/interrupts will work, and revamped the instruction-set documentation on the project page into a nice clean table format that should make things a bit clearer. The simulator is currently undergoing a major overhaul, partly to implement interrupts, but mostly to add non-blocking I/O* on *nix (and eventually Windows) hosts, so that the simulation can run in "real time." UART I/O is pretty nearly done, after much banging of the head against termios and direct *nix file I/O functions; next I get to bang my head against asynchronous file access for the disk image, oh boy :/
* (Somehow I've been doing hobbyist programming in C for upwards of fifteen years and I've never had the occasion, until now, to discover that plain ANSI C just doesn't offer any means at all to distinguish "no more data" from "no more data currently." Really, K&R? Really?)
Also, because I never have just one project when I can have two or three projects, I've started sketching out a 32-bit extension to the architecture ;D I like to think that, if this is my retro-'70s minicomputer design, however many years down the line I get around to learning FPGAs, that'll be my retro-'90s pizzabox workstation design ;)
_________________ "'Legacy code' often differs from its suggested alternative by actually working and scaling." - Bjarne Stroustrup
|
Mon Jan 17, 2022 2:01 am |
|
Who is online |
Users browsing this forum: CCBot and 0 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|